1 /** 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 17 package android.app.usage; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.annotation.Nullable; 22 import android.annotation.SystemService; 23 import android.annotation.TestApi; 24 import android.annotation.UnsupportedAppUsage; 25 import android.app.usage.NetworkStats.Bucket; 26 import android.content.Context; 27 import android.net.ConnectivityManager; 28 import android.net.DataUsageRequest; 29 import android.net.INetworkStatsService; 30 import android.net.NetworkIdentity; 31 import android.net.NetworkTemplate; 32 import android.os.Binder; 33 import android.os.Handler; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.Messenger; 37 import android.os.RemoteException; 38 import android.os.ServiceManager; 39 import android.os.ServiceManager.ServiceNotFoundException; 40 import android.util.DataUnit; 41 import android.util.Log; 42 43 import com.android.internal.annotations.VisibleForTesting; 44 45 /** 46 * Provides access to network usage history and statistics. Usage data is collected in 47 * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. 48 * <p /> 49 * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and 50 * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain 51 * data about themselves. See the below note for special cases in which apps can obtain data about 52 * other applications. 53 * <h3> 54 * Summary queries 55 * </h3> 56 * {@link #querySummaryForDevice} <p /> 57 * {@link #querySummaryForUser} <p /> 58 * {@link #querySummary} <p /> 59 * These queries aggregate network usage across the whole interval. Therefore there will be only one 60 * bucket for a particular key, state, metered and roaming combination. In case of the user-wide 61 * and device-wide summaries a single bucket containing the totalised network usage is returned. 62 * <h3> 63 * History queries 64 * </h3> 65 * {@link #queryDetailsForUid} <p /> 66 * {@link #queryDetails} <p /> 67 * These queries do not aggregate over time but do aggregate over state, metered and roaming. 68 * Therefore there can be multiple buckets for a particular key. However, all Buckets will have 69 * {@code state} {@link NetworkStats.Bucket#STATE_ALL}, 70 * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 71 * {@code metered } {@link NetworkStats.Bucket#METERED_ALL}, 72 * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}. 73 * <p /> 74 * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the 75 * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, 76 * which is a system-level permission and will not be granted to third-party apps. However, 77 * declaring the permission implies intention to use the API and the user of the device can grant 78 * permission through the Settings application. 79 * <p /> 80 * Profile owner apps are automatically granted permission to query data on the profile they manage 81 * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier- 82 * privileged apps likewise get access to usage data for all users on the device. 83 * <p /> 84 * In addition to tethering usage, usage by removed users and apps, and usage by the system 85 * is also included in the results for callers with one of these higher levels of access. 86 * <p /> 87 * <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required 88 * the above permission, even to access an app's own data usage, and carrier-privileged apps were 89 * not included. 90 */ 91 @SystemService(Context.NETWORK_STATS_SERVICE) 92 public class NetworkStatsManager { 93 private static final String TAG = "NetworkStatsManager"; 94 private static final boolean DBG = false; 95 96 /** @hide */ 97 public static final int CALLBACK_LIMIT_REACHED = 0; 98 /** @hide */ 99 public static final int CALLBACK_RELEASED = 1; 100 101 /** 102 * Minimum data usage threshold for registering usage callbacks. 103 * 104 * Requests registered with a threshold lower than this will only be triggered once this minimum 105 * is reached. 106 * @hide 107 */ 108 public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2); 109 110 private final Context mContext; 111 private final INetworkStatsService mService; 112 113 /** @hide */ 114 public static final int FLAG_POLL_ON_OPEN = 1 << 0; 115 /** @hide */ 116 public static final int FLAG_POLL_FORCE = 1 << 1; 117 /** @hide */ 118 public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2; 119 120 private int mFlags; 121 122 /** 123 * {@hide} 124 */ 125 @UnsupportedAppUsage NetworkStatsManager(Context context)126 public NetworkStatsManager(Context context) throws ServiceNotFoundException { 127 this(context, INetworkStatsService.Stub.asInterface( 128 ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); 129 } 130 131 /** @hide */ 132 @VisibleForTesting NetworkStatsManager(Context context, INetworkStatsService service)133 public NetworkStatsManager(Context context, INetworkStatsService service) { 134 mContext = context; 135 mService = service; 136 setPollOnOpen(true); 137 } 138 139 /** @hide */ setPollOnOpen(boolean pollOnOpen)140 public void setPollOnOpen(boolean pollOnOpen) { 141 if (pollOnOpen) { 142 mFlags |= FLAG_POLL_ON_OPEN; 143 } else { 144 mFlags &= ~FLAG_POLL_ON_OPEN; 145 } 146 } 147 148 /** @hide */ 149 @TestApi setPollForce(boolean pollForce)150 public void setPollForce(boolean pollForce) { 151 if (pollForce) { 152 mFlags |= FLAG_POLL_FORCE; 153 } else { 154 mFlags &= ~FLAG_POLL_FORCE; 155 } 156 } 157 158 /** @hide */ setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan)159 public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) { 160 if (augmentWithSubscriptionPlan) { 161 mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; 162 } else { 163 mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; 164 } 165 } 166 167 /** @hide */ querySummaryForDevice(NetworkTemplate template, long startTime, long endTime)168 public Bucket querySummaryForDevice(NetworkTemplate template, 169 long startTime, long endTime) throws SecurityException, RemoteException { 170 Bucket bucket = null; 171 NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, 172 mService); 173 bucket = stats.getDeviceSummaryForNetwork(); 174 175 stats.close(); 176 return bucket; 177 } 178 179 /** 180 * Query network usage statistics summaries. Result is summarised data usage for the whole 181 * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and 182 * roaming. This means the bucket's start and end timestamp are going to be the same as the 183 * 'startTime' and 'endTime' parameters. State is going to be 184 * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, 185 * tag {@link NetworkStats.Bucket#TAG_NONE}, 186 * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 187 * metered {@link NetworkStats.Bucket#METERED_ALL}, 188 * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. 189 * 190 * @param networkType As defined in {@link ConnectivityManager}, e.g. 191 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 192 * etc. 193 * @param subscriberId If applicable, the subscriber id of the network interface. 194 * @param startTime Start of period. Defined in terms of "Unix time", see 195 * {@link java.lang.System#currentTimeMillis}. 196 * @param endTime End of period. Defined in terms of "Unix time", see 197 * {@link java.lang.System#currentTimeMillis}. 198 * @return Bucket object or null if permissions are insufficient or error happened during 199 * statistics collection. 200 */ querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime)201 public Bucket querySummaryForDevice(int networkType, String subscriberId, 202 long startTime, long endTime) throws SecurityException, RemoteException { 203 NetworkTemplate template; 204 try { 205 template = createTemplate(networkType, subscriberId); 206 } catch (IllegalArgumentException e) { 207 if (DBG) Log.e(TAG, "Cannot create template", e); 208 return null; 209 } 210 211 return querySummaryForDevice(template, startTime, endTime); 212 } 213 214 /** 215 * Query network usage statistics summaries. Result is summarised data usage for all uids 216 * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. 217 * This means the bucket's start and end timestamp are going to be the same as the 'startTime' 218 * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, 219 * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, 220 * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming 221 * {@link NetworkStats.Bucket#ROAMING_ALL}. 222 * 223 * @param networkType As defined in {@link ConnectivityManager}, e.g. 224 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 225 * etc. 226 * @param subscriberId If applicable, the subscriber id of the network interface. 227 * @param startTime Start of period. Defined in terms of "Unix time", see 228 * {@link java.lang.System#currentTimeMillis}. 229 * @param endTime End of period. Defined in terms of "Unix time", see 230 * {@link java.lang.System#currentTimeMillis}. 231 * @return Bucket object or null if permissions are insufficient or error happened during 232 * statistics collection. 233 */ querySummaryForUser(int networkType, String subscriberId, long startTime, long endTime)234 public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, 235 long endTime) throws SecurityException, RemoteException { 236 NetworkTemplate template; 237 try { 238 template = createTemplate(networkType, subscriberId); 239 } catch (IllegalArgumentException e) { 240 if (DBG) Log.e(TAG, "Cannot create template", e); 241 return null; 242 } 243 244 NetworkStats stats; 245 stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 246 stats.startSummaryEnumeration(); 247 248 stats.close(); 249 return stats.getSummaryAggregate(); 250 } 251 252 /** 253 * Query network usage statistics summaries. Result filtered to include only uids belonging to 254 * calling user. Result is aggregated over time, hence all buckets will have the same start and 255 * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This 256 * means buckets' start and end timestamps are going to be the same as the 'startTime' and 257 * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to 258 * be the same. 259 * 260 * @param networkType As defined in {@link ConnectivityManager}, e.g. 261 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 262 * etc. 263 * @param subscriberId If applicable, the subscriber id of the network interface. 264 * @param startTime Start of period. Defined in terms of "Unix time", see 265 * {@link java.lang.System#currentTimeMillis}. 266 * @param endTime End of period. Defined in terms of "Unix time", see 267 * {@link java.lang.System#currentTimeMillis}. 268 * @return Statistics object or null if permissions are insufficient or error happened during 269 * statistics collection. 270 */ querySummary(int networkType, String subscriberId, long startTime, long endTime)271 public NetworkStats querySummary(int networkType, String subscriberId, long startTime, 272 long endTime) throws SecurityException, RemoteException { 273 NetworkTemplate template; 274 try { 275 template = createTemplate(networkType, subscriberId); 276 } catch (IllegalArgumentException e) { 277 if (DBG) Log.e(TAG, "Cannot create template", e); 278 return null; 279 } 280 281 return querySummary(template, startTime, endTime); 282 } 283 284 /** @hide */ querySummary(NetworkTemplate template, long startTime, long endTime)285 public NetworkStats querySummary(NetworkTemplate template, long startTime, 286 long endTime) throws SecurityException, RemoteException { 287 NetworkStats result; 288 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 289 result.startSummaryEnumeration(); 290 291 return result; 292 } 293 294 /** 295 * Query network usage statistics details for a given uid. 296 * 297 * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) 298 */ queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid)299 public NetworkStats queryDetailsForUid(int networkType, String subscriberId, 300 long startTime, long endTime, int uid) throws SecurityException { 301 return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, 302 NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); 303 } 304 305 /** @hide */ queryDetailsForUid(NetworkTemplate template, long startTime, long endTime, int uid)306 public NetworkStats queryDetailsForUid(NetworkTemplate template, 307 long startTime, long endTime, int uid) throws SecurityException { 308 return queryDetailsForUidTagState(template, startTime, endTime, uid, 309 NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); 310 } 311 312 /** 313 * Query network usage statistics details for a given uid and tag. 314 * 315 * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) 316 */ queryDetailsForUidTag(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag)317 public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, 318 long startTime, long endTime, int uid, int tag) throws SecurityException { 319 return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, 320 tag, NetworkStats.Bucket.STATE_ALL); 321 } 322 323 /** 324 * Query network usage statistics details for a given uid, tag, and state. Only usable for uids 325 * belonging to calling user. Result is not aggregated over time. This means buckets' start and 326 * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going 327 * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state 328 * the same as the 'state' parameter. 329 * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 330 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and 331 * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. 332 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't 333 * interpolate across partial buckets. Since bucket length is in the order of hours, this 334 * method cannot be used to measure data usage on a fine grained time scale. 335 * 336 * @param networkType As defined in {@link ConnectivityManager}, e.g. 337 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 338 * etc. 339 * @param subscriberId If applicable, the subscriber id of the network interface. 340 * @param startTime Start of period. Defined in terms of "Unix time", see 341 * {@link java.lang.System#currentTimeMillis}. 342 * @param endTime End of period. Defined in terms of "Unix time", see 343 * {@link java.lang.System#currentTimeMillis}. 344 * @param uid UID of app 345 * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags. 346 * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate 347 * traffic from all states. 348 * @return Statistics object or null if an error happened during statistics collection. 349 * @throws SecurityException if permissions are insufficient to read network statistics. 350 */ queryDetailsForUidTagState(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag, int state)351 public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId, 352 long startTime, long endTime, int uid, int tag, int state) throws SecurityException { 353 NetworkTemplate template; 354 template = createTemplate(networkType, subscriberId); 355 356 return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state); 357 } 358 359 /** @hide */ queryDetailsForUidTagState(NetworkTemplate template, long startTime, long endTime, int uid, int tag, int state)360 public NetworkStats queryDetailsForUidTagState(NetworkTemplate template, 361 long startTime, long endTime, int uid, int tag, int state) throws SecurityException { 362 363 NetworkStats result; 364 try { 365 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 366 result.startHistoryEnumeration(uid, tag, state); 367 } catch (RemoteException e) { 368 Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag 369 + " state=" + state, e); 370 return null; 371 } 372 373 return result; 374 } 375 376 /** 377 * Query network usage statistics details. Result filtered to include only uids belonging to 378 * calling user. Result is aggregated over state but not aggregated over time, uid, tag, 379 * metered, nor roaming. This means buckets' start and end timestamps are going to be between 380 * 'startTime' and 'endTime' parameters. State is going to be 381 * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, 382 * tag {@link NetworkStats.Bucket#TAG_NONE}, 383 * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 384 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, 385 * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. 386 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't 387 * interpolate across partial buckets. Since bucket length is in the order of hours, this 388 * method cannot be used to measure data usage on a fine grained time scale. 389 * 390 * @param networkType As defined in {@link ConnectivityManager}, e.g. 391 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 392 * etc. 393 * @param subscriberId If applicable, the subscriber id of the network interface. 394 * @param startTime Start of period. Defined in terms of "Unix time", see 395 * {@link java.lang.System#currentTimeMillis}. 396 * @param endTime End of period. Defined in terms of "Unix time", see 397 * {@link java.lang.System#currentTimeMillis}. 398 * @return Statistics object or null if permissions are insufficient or error happened during 399 * statistics collection. 400 */ queryDetails(int networkType, String subscriberId, long startTime, long endTime)401 public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, 402 long endTime) throws SecurityException, RemoteException { 403 NetworkTemplate template; 404 try { 405 template = createTemplate(networkType, subscriberId); 406 } catch (IllegalArgumentException e) { 407 if (DBG) Log.e(TAG, "Cannot create template", e); 408 return null; 409 } 410 411 NetworkStats result; 412 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 413 result.startUserUidEnumeration(); 414 return result; 415 } 416 417 /** @hide */ registerUsageCallback(NetworkTemplate template, int networkType, long thresholdBytes, UsageCallback callback, @Nullable Handler handler)418 public void registerUsageCallback(NetworkTemplate template, int networkType, 419 long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { 420 checkNotNull(callback, "UsageCallback cannot be null"); 421 422 final Looper looper; 423 if (handler == null) { 424 looper = Looper.myLooper(); 425 } else { 426 looper = handler.getLooper(); 427 } 428 429 DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, 430 template, thresholdBytes); 431 try { 432 CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, 433 template.getSubscriberId(), callback); 434 callback.request = mService.registerUsageCallback( 435 mContext.getOpPackageName(), request, new Messenger(callbackHandler), 436 new Binder()); 437 if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); 438 439 if (callback.request == null) { 440 Log.e(TAG, "Request from callback is null; should not happen"); 441 } 442 } catch (RemoteException e) { 443 if (DBG) Log.d(TAG, "Remote exception when registering callback"); 444 throw e.rethrowFromSystemServer(); 445 } 446 } 447 448 /** 449 * Registers to receive notifications about data usage on specified networks. 450 * 451 * #see registerUsageCallback(int, String[], long, UsageCallback, Handler) 452 */ registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback)453 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, 454 UsageCallback callback) { 455 registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, 456 null /* handler */); 457 } 458 459 /** 460 * Registers to receive notifications about data usage on specified networks. 461 * 462 * <p>The callbacks will continue to be called as long as the process is live or 463 * {@link #unregisterUsageCallback} is called. 464 * 465 * @param networkType Type of network to monitor. Either 466 {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. 467 * @param subscriberId If applicable, the subscriber id of the network interface. 468 * @param thresholdBytes Threshold in bytes to be notified on. 469 * @param callback The {@link UsageCallback} that the system will call when data usage 470 * has exceeded the specified threshold. 471 * @param handler to dispatch callback events through, otherwise if {@code null} it uses 472 * the calling thread. 473 */ registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback, @Nullable Handler handler)474 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, 475 UsageCallback callback, @Nullable Handler handler) { 476 NetworkTemplate template = createTemplate(networkType, subscriberId); 477 if (DBG) { 478 Log.d(TAG, "registerUsageCallback called with: {" 479 + " networkType=" + networkType 480 + " subscriberId=" + subscriberId 481 + " thresholdBytes=" + thresholdBytes 482 + " }"); 483 } 484 registerUsageCallback(template, networkType, thresholdBytes, callback, handler); 485 } 486 487 /** 488 * Unregisters callbacks on data usage. 489 * 490 * @param callback The {@link UsageCallback} used when registering. 491 */ unregisterUsageCallback(UsageCallback callback)492 public void unregisterUsageCallback(UsageCallback callback) { 493 if (callback == null || callback.request == null 494 || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { 495 throw new IllegalArgumentException("Invalid UsageCallback"); 496 } 497 try { 498 mService.unregisterUsageRequest(callback.request); 499 } catch (RemoteException e) { 500 if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); 501 throw e.rethrowFromSystemServer(); 502 } 503 } 504 505 /** 506 * Base class for usage callbacks. Should be extended by applications wanting notifications. 507 */ 508 public static abstract class UsageCallback { 509 510 /** 511 * Called when data usage has reached the given threshold. 512 */ onThresholdReached(int networkType, String subscriberId)513 public abstract void onThresholdReached(int networkType, String subscriberId); 514 515 /** 516 * @hide used for internal bookkeeping 517 */ 518 private DataUsageRequest request; 519 } 520 createTemplate(int networkType, String subscriberId)521 private static NetworkTemplate createTemplate(int networkType, String subscriberId) { 522 final NetworkTemplate template; 523 switch (networkType) { 524 case ConnectivityManager.TYPE_MOBILE: 525 template = subscriberId == null 526 ? NetworkTemplate.buildTemplateMobileWildcard() 527 : NetworkTemplate.buildTemplateMobileAll(subscriberId); 528 break; 529 case ConnectivityManager.TYPE_WIFI: 530 template = NetworkTemplate.buildTemplateWifiWildcard(); 531 break; 532 default: 533 throw new IllegalArgumentException("Cannot create template for network type " 534 + networkType + ", subscriberId '" 535 + NetworkIdentity.scrubSubscriberId(subscriberId) + "'."); 536 } 537 return template; 538 } 539 540 private static class CallbackHandler extends Handler { 541 private final int mNetworkType; 542 private final String mSubscriberId; 543 private UsageCallback mCallback; 544 CallbackHandler(Looper looper, int networkType, String subscriberId, UsageCallback callback)545 CallbackHandler(Looper looper, int networkType, String subscriberId, 546 UsageCallback callback) { 547 super(looper); 548 mNetworkType = networkType; 549 mSubscriberId = subscriberId; 550 mCallback = callback; 551 } 552 553 @Override handleMessage(Message message)554 public void handleMessage(Message message) { 555 DataUsageRequest request = 556 (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY); 557 558 switch (message.what) { 559 case CALLBACK_LIMIT_REACHED: { 560 if (mCallback != null) { 561 mCallback.onThresholdReached(mNetworkType, mSubscriberId); 562 } else { 563 Log.e(TAG, "limit reached with released callback for " + request); 564 } 565 break; 566 } 567 case CALLBACK_RELEASED: { 568 if (DBG) Log.d(TAG, "callback released for " + request); 569 mCallback = null; 570 break; 571 } 572 } 573 } 574 getObject(Message msg, String key)575 private static Object getObject(Message msg, String key) { 576 return msg.getData().getParcelable(key); 577 } 578 } 579 } 580