blob: e805fabc796727de69352571b43b26af830b7aac [file] [log] [blame]
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +00001/**
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package android.app.usage;
18
Antonio Cansadoba8288d2015-12-02 08:42:54 -080019import static com.android.internal.util.Preconditions.checkNotNull;
20
21import android.annotation.Nullable;
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010022import android.app.usage.NetworkStats.Bucket;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000023import android.content.Context;
24import android.net.ConnectivityManager;
Antonio Cansadoba8288d2015-12-02 08:42:54 -080025import android.net.DataUsageRequest;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000026import android.net.NetworkIdentity;
27import android.net.NetworkTemplate;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080028import android.net.INetworkStatsService;
29import android.os.Binder;
Jeff Davidson1efb1332015-12-09 18:04:50 -080030import android.os.Build;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080031import android.os.Message;
32import android.os.Messenger;
Antonio Cansadoba8288d2015-12-02 08:42:54 -080033import android.os.Handler;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080034import android.os.Looper;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000035import android.os.RemoteException;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080036import android.os.ServiceManager;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060037import android.os.ServiceManager.ServiceNotFoundException;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000038import android.util.Log;
39
40/**
41 * Provides access to network usage history and statistics. Usage data is collected in
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010042 * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000043 * <p />
44 * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
Jeff Davidson1efb1332015-12-09 18:04:50 -080045 * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain
46 * data about themselves. See the below note for special cases in which apps can obtain data about
47 * other applications.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000048 * <h3>
49 * Summary queries
50 * </h3>
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010051 * {@link #querySummaryForDevice} <p />
52 * {@link #querySummaryForUser} <p />
53 * {@link #querySummary} <p />
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000054 * These queries aggregate network usage across the whole interval. Therefore there will be only one
Jeff Davidsona6a78072016-01-11 16:02:17 -080055 * bucket for a particular key and state and roaming combination. In case of the user-wide and
56 * device-wide summaries a single bucket containing the totalised network usage is returned.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000057 * <h3>
58 * History queries
59 * </h3>
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010060 * {@link #queryDetailsForUid} <p />
61 * {@link #queryDetails} <p />
Jeff Davidsona6a78072016-01-11 16:02:17 -080062 * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there
63 * can be multiple buckets for a particular key but all Bucket's state is going to be
64 * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be
65 * {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000066 * <p />
Zoltan Szatmary-Ban3a8b3432016-01-21 10:44:37 +000067 * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
68 * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS},
69 * which is a system-level permission and will not be granted to third-party apps. However,
70 * declaring the permission implies intention to use the API and the user of the device can grant
71 * permission through the Settings application.
72 * <p />
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000073 * Profile owner apps are automatically granted permission to query data on the profile they manage
Jeff Davidson1efb1332015-12-09 18:04:50 -080074 * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
75 * privileged apps likewise get access to usage data for all users on the device.
76 * <p />
77 * In addition to tethering usage, usage by removed users and apps, and usage by the system
78 * is also included in the results for callers with one of these higher levels of access.
79 * <p />
80 * <b>NOTE:</b> Prior to API level {@value Build.VERSION_CODES#N}, all calls to these APIs required
81 * the above permission, even to access an app's own data usage, and carrier-privileged apps were
82 * not included.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000083 */
84public class NetworkStatsManager {
Antonio Cansadocd42acd2016-02-17 13:03:38 -080085 private static final String TAG = "NetworkStatsManager";
86 private static final boolean DBG = false;
87
88 /** @hide */
89 public static final int CALLBACK_LIMIT_REACHED = 0;
90 /** @hide */
91 public static final int CALLBACK_RELEASED = 1;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000092
93 private final Context mContext;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080094 private final INetworkStatsService mService;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000095
96 /**
97 * {@hide}
98 */
Jeff Sharkey49ca5292016-05-10 12:54:45 -060099 public NetworkStatsManager(Context context) throws ServiceNotFoundException {
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000100 mContext = context;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800101 mService = INetworkStatsService.Stub.asInterface(
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600102 ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE));
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000103 }
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800104
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000105 /**
106 * Query network usage statistics summaries. Result is summarised data usage for the whole
Antonio Cansado46c753672015-12-10 15:57:56 -0800107 * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
108 * means the bucket's start and end timestamp are going to be the same as the 'startTime' and
109 * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
Antonio Cansado6965c182016-03-30 11:37:18 -0700110 * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}
Antonio Cansado46c753672015-12-10 15:57:56 -0800111 * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000112 *
113 * @param networkType As defined in {@link ConnectivityManager}, e.g.
114 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
115 * etc.
116 * @param subscriberId If applicable, the subscriber id of the network interface.
117 * @param startTime Start of period. Defined in terms of "Unix time", see
118 * {@link java.lang.System#currentTimeMillis}.
119 * @param endTime End of period. Defined in terms of "Unix time", see
120 * {@link java.lang.System#currentTimeMillis}.
121 * @return Bucket object or null if permissions are insufficient or error happened during
122 * statistics collection.
123 */
124 public Bucket querySummaryForDevice(int networkType, String subscriberId,
125 long startTime, long endTime) throws SecurityException, RemoteException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700126 NetworkTemplate template;
127 try {
128 template = createTemplate(networkType, subscriberId);
129 } catch (IllegalArgumentException e) {
130 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000131 return null;
132 }
133
134 Bucket bucket = null;
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100135 NetworkStats stats = new NetworkStats(mContext, template, startTime, endTime);
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100136 bucket = stats.getDeviceSummaryForNetwork();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000137
138 stats.close();
139 return bucket;
140 }
141
142 /**
143 * Query network usage statistics summaries. Result is summarised data usage for all uids
144 * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100145 * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
Antonio Cansado6965c182016-03-30 11:37:18 -0700146 * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
Antonio Cansado46c753672015-12-10 15:57:56 -0800147 * {@link NetworkStats.Bucket#UID_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000148 *
149 * @param networkType As defined in {@link ConnectivityManager}, e.g.
150 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
151 * etc.
152 * @param subscriberId If applicable, the subscriber id of the network interface.
153 * @param startTime Start of period. Defined in terms of "Unix time", see
154 * {@link java.lang.System#currentTimeMillis}.
155 * @param endTime End of period. Defined in terms of "Unix time", see
156 * {@link java.lang.System#currentTimeMillis}.
157 * @return Bucket object or null if permissions are insufficient or error happened during
158 * statistics collection.
159 */
160 public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
Antonio Cansado6965c182016-03-30 11:37:18 -0700161 long endTime) throws SecurityException, RemoteException {
162 NetworkTemplate template;
163 try {
164 template = createTemplate(networkType, subscriberId);
165 } catch (IllegalArgumentException e) {
166 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000167 return null;
168 }
169
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100170 NetworkStats stats;
171 stats = new NetworkStats(mContext, template, startTime, endTime);
Antonio Cansado6965c182016-03-30 11:37:18 -0700172 stats.startSummaryEnumeration();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000173
174 stats.close();
175 return stats.getSummaryAggregate();
176 }
177
178 /**
179 * Query network usage statistics summaries. Result filtered to include only uids belonging to
180 * calling user. Result is aggregated over time, hence all buckets will have the same start and
Antonio Cansado6965c182016-03-30 11:37:18 -0700181 * end timestamps. Not aggregated over state or uid. This means buckets' start and end
182 * timestamps are going to be the same as the 'startTime' and 'endTime' parameters.
183 * State and uid are going to vary, and tag is going to be the same.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000184 *
185 * @param networkType As defined in {@link ConnectivityManager}, e.g.
186 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
187 * etc.
188 * @param subscriberId If applicable, the subscriber id of the network interface.
189 * @param startTime Start of period. Defined in terms of "Unix time", see
190 * {@link java.lang.System#currentTimeMillis}.
191 * @param endTime End of period. Defined in terms of "Unix time", see
192 * {@link java.lang.System#currentTimeMillis}.
193 * @return Statistics object or null if permissions are insufficient or error happened during
194 * statistics collection.
195 */
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100196 public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
Antonio Cansado6965c182016-03-30 11:37:18 -0700197 long endTime) throws SecurityException, RemoteException {
198 NetworkTemplate template;
199 try {
200 template = createTemplate(networkType, subscriberId);
201 } catch (IllegalArgumentException e) {
202 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000203 return null;
204 }
205
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100206 NetworkStats result;
207 result = new NetworkStats(mContext, template, startTime, endTime);
Antonio Cansado6965c182016-03-30 11:37:18 -0700208 result.startSummaryEnumeration();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000209
210 return result;
211 }
212
213 /**
Antonio Cansado46c753672015-12-10 15:57:56 -0800214 * Query network usage statistics details for a given uid.
215 *
216 * #see queryDetailsForUidTag(int, String, long, long, int, int)
217 */
218 public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
219 long startTime, long endTime, int uid) throws SecurityException, RemoteException {
220 return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid,
Antonio Cansado6965c182016-03-30 11:37:18 -0700221 NetworkStats.Bucket.TAG_NONE);
Antonio Cansado46c753672015-12-10 15:57:56 -0800222 }
223
224 /**
225 * Query network usage statistics details for a given uid and tag. Only usable for uids
226 * belonging to calling user. Result is aggregated over state but not aggregated over time.
227 * This means buckets' start and end timestamps are going to be between 'startTime' and
228 * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the
229 * same as the 'uid' parameter and tag the same as 'tag' parameter.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100230 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
231 * interpolate across partial buckets. Since bucket length is in the order of hours, this
232 * method cannot be used to measure data usage on a fine grained time scale.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000233 *
234 * @param networkType As defined in {@link ConnectivityManager}, e.g.
235 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
236 * etc.
237 * @param subscriberId If applicable, the subscriber id of the network interface.
238 * @param startTime Start of period. Defined in terms of "Unix time", see
239 * {@link java.lang.System#currentTimeMillis}.
240 * @param endTime End of period. Defined in terms of "Unix time", see
241 * {@link java.lang.System#currentTimeMillis}.
242 * @param uid UID of app
Antonio Cansado6965c182016-03-30 11:37:18 -0700243 * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags.
Antonio Cansado904237f2016-05-25 09:57:21 -0700244 * @return Statistics object or null if an error happened during statistics collection.
245 * @throws SecurityException if permissions are insufficient to read network statistics.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000246 */
Antonio Cansado46c753672015-12-10 15:57:56 -0800247 public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
Antonio Cansado904237f2016-05-25 09:57:21 -0700248 long startTime, long endTime, int uid, int tag) throws SecurityException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700249 NetworkTemplate template;
Antonio Cansado904237f2016-05-25 09:57:21 -0700250 template = createTemplate(networkType, subscriberId);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000251
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100252 NetworkStats result;
Antonio Cansado6965c182016-03-30 11:37:18 -0700253 try {
254 result = new NetworkStats(mContext, template, startTime, endTime);
255 result.startHistoryEnumeration(uid, tag);
256 } catch (RemoteException e) {
257 Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
258 return null;
259 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000260
261 return result;
262 }
263
264 /**
265 * Query network usage statistics details. Result filtered to include only uids belonging to
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100266 * calling user. Result is aggregated over state but not aggregated over time or uid. This means
267 * buckets' start and end timestamps are going to be between 'startTime' and 'endTime'
Antonio Cansado46c753672015-12-10 15:57:56 -0800268 * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
Antonio Cansado6965c182016-03-30 11:37:18 -0700269 * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be
Antonio Cansado46c753672015-12-10 15:57:56 -0800270 * {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100271 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
272 * interpolate across partial buckets. Since bucket length is in the order of hours, this
273 * method cannot be used to measure data usage on a fine grained time scale.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000274 *
275 * @param networkType As defined in {@link ConnectivityManager}, e.g.
276 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
277 * etc.
278 * @param subscriberId If applicable, the subscriber id of the network interface.
279 * @param startTime Start of period. Defined in terms of "Unix time", see
280 * {@link java.lang.System#currentTimeMillis}.
281 * @param endTime End of period. Defined in terms of "Unix time", see
282 * {@link java.lang.System#currentTimeMillis}.
283 * @return Statistics object or null if permissions are insufficient or error happened during
284 * statistics collection.
285 */
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100286 public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000287 long endTime) throws SecurityException, RemoteException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700288 NetworkTemplate template;
289 try {
290 template = createTemplate(networkType, subscriberId);
291 } catch (IllegalArgumentException e) {
292 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000293 return null;
294 }
Antonio Cansado6965c182016-03-30 11:37:18 -0700295
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100296 NetworkStats result;
297 result = new NetworkStats(mContext, template, startTime, endTime);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000298 result.startUserUidEnumeration();
299 return result;
300 }
301
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800302 /**
Antonio Cansado6965c182016-03-30 11:37:18 -0700303 * Registers to receive notifications about data usage on specified networks.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800304 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700305 * #see registerUsageCallback(int, String[], long, UsageCallback, Handler)
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800306 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700307 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
308 UsageCallback callback) {
Antonio Cansadof7048372016-06-20 15:03:03 -0700309 registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
310 null /* handler */);
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800311 }
312
313 /**
Antonio Cansado6965c182016-03-30 11:37:18 -0700314 * Registers to receive notifications about data usage on specified networks.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800315 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700316 * <p>The callbacks will continue to be called as long as the process is live or
317 * {@link #unregisterUsageCallback} is called.
318 *
319 * @param networkType Type of network to monitor. Either
320 {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
321 * @param subscriberId If applicable, the subscriber id of the network interface.
322 * @param thresholdBytes Threshold in bytes to be notified on.
323 * @param callback The {@link UsageCallback} that the system will call when data usage
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800324 * has exceeded the specified threshold.
325 * @param handler to dispatch callback events through, otherwise if {@code null} it uses
326 * the calling thread.
327 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700328 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
329 UsageCallback callback, @Nullable Handler handler) {
330 checkNotNull(callback, "UsageCallback cannot be null");
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800331
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800332 final Looper looper;
333 if (handler == null) {
334 looper = Looper.myLooper();
335 } else {
336 looper = handler.getLooper();
337 }
338
Antonio Cansado6965c182016-03-30 11:37:18 -0700339 if (DBG) {
340 Log.d(TAG, "registerUsageCallback called with: {"
341 + " networkType=" + networkType
342 + " subscriberId=" + subscriberId
343 + " thresholdBytes=" + thresholdBytes
344 + " }");
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800345 }
Antonio Cansado6965c182016-03-30 11:37:18 -0700346
347 NetworkTemplate template = createTemplate(networkType, subscriberId);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800348 DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
Antonio Cansado6965c182016-03-30 11:37:18 -0700349 template, thresholdBytes);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800350 try {
Antonio Cansado6965c182016-03-30 11:37:18 -0700351 CallbackHandler callbackHandler = new CallbackHandler(looper, networkType,
352 subscriberId, callback);
353 callback.request = mService.registerUsageCallback(
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800354 mContext.getOpPackageName(), request, new Messenger(callbackHandler),
355 new Binder());
Antonio Cansado6965c182016-03-30 11:37:18 -0700356 if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800357
358 if (callback.request == null) {
359 Log.e(TAG, "Request from callback is null; should not happen");
360 }
361 } catch (RemoteException e) {
362 if (DBG) Log.d(TAG, "Remote exception when registering callback");
Antonio Cansado6965c182016-03-30 11:37:18 -0700363 throw e.rethrowFromSystemServer();
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800364 }
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800365 }
366
367 /**
368 * Unregisters callbacks on data usage.
369 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700370 * @param callback The {@link UsageCallback} used when registering.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800371 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700372 public void unregisterUsageCallback(UsageCallback callback) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800373 if (callback == null || callback.request == null
374 || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
Antonio Cansado6965c182016-03-30 11:37:18 -0700375 throw new IllegalArgumentException("Invalid UsageCallback");
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800376 }
377 try {
Antonio Cansado6965c182016-03-30 11:37:18 -0700378 mService.unregisterUsageRequest(callback.request);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800379 } catch (RemoteException e) {
380 if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
Antonio Cansado6965c182016-03-30 11:37:18 -0700381 throw e.rethrowFromSystemServer();
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800382 }
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800383 }
384
Antonio Cansado6965c182016-03-30 11:37:18 -0700385 /**
386 * Base class for usage callbacks. Should be extended by applications wanting notifications.
387 */
388 public static abstract class UsageCallback {
389
390 /**
391 * Called when data usage has reached the given threshold.
392 */
393 public abstract void onThresholdReached(int networkType, String subscriberId);
394
395 /**
396 * @hide used for internal bookkeeping
397 */
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800398 private DataUsageRequest request;
399 }
400
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000401 private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
402 NetworkTemplate template = null;
403 switch (networkType) {
404 case ConnectivityManager.TYPE_MOBILE: {
405 template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
406 } break;
407 case ConnectivityManager.TYPE_WIFI: {
408 template = NetworkTemplate.buildTemplateWifiWildcard();
409 } break;
410 default: {
Antonio Cansado6965c182016-03-30 11:37:18 -0700411 throw new IllegalArgumentException("Cannot create template for network type "
412 + networkType + ", subscriberId '"
413 + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000414 }
415 }
416 return template;
417 }
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800418
419 private static class CallbackHandler extends Handler {
Antonio Cansado6965c182016-03-30 11:37:18 -0700420 private final int mNetworkType;
421 private final String mSubscriberId;
422 private UsageCallback mCallback;
423
424 CallbackHandler(Looper looper, int networkType, String subscriberId,
425 UsageCallback callback) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800426 super(looper);
Antonio Cansado6965c182016-03-30 11:37:18 -0700427 mNetworkType = networkType;
428 mSubscriberId = subscriberId;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800429 mCallback = callback;
430 }
431
432 @Override
433 public void handleMessage(Message message) {
434 DataUsageRequest request =
435 (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
436
437 switch (message.what) {
438 case CALLBACK_LIMIT_REACHED: {
439 if (mCallback != null) {
Antonio Cansado6965c182016-03-30 11:37:18 -0700440 mCallback.onThresholdReached(mNetworkType, mSubscriberId);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800441 } else {
442 Log.e(TAG, "limit reached with released callback for " + request);
443 }
444 break;
445 }
446 case CALLBACK_RELEASED: {
447 if (DBG) Log.d(TAG, "callback released for " + request);
448 mCallback = null;
449 break;
450 }
451 }
452 }
453
454 private static Object getObject(Message msg, String key) {
455 return msg.getData().getParcelable(key);
456 }
457 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000458}