1 /* 2 * Copyright 2016, 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.managedprovisioning.analytics; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; 22 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE; 23 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_UNSPECIFIED; 24 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED; 25 import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_DPC_SETUP_COMPLETED; 26 import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_DPC_SETUP_STARTED; 27 import static android.stats.devicepolicy.DevicePolicyEnums.PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE; 28 29 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ACTION; 30 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_CANCELLED; 31 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_COPY_ACCOUNT_STATUS; 32 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_INSTALLED_BY_PACKAGE; 33 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_DPC_PACKAGE_NAME; 34 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_NFC; 35 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_QR_CODE; 36 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE; 37 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ERROR; 38 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_EXTRA; 39 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_COMPLETED; 40 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_SESSION_STARTED; 41 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_COUNT; 42 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_TERMS_READ; 43 44 import android.annotation.IntDef; 45 import android.app.admin.DevicePolicyEventLogger; 46 import android.app.admin.DevicePolicyManager; 47 import android.content.ComponentName; 48 import android.content.Context; 49 import android.content.Intent; 50 import android.stats.devicepolicy.DevicePolicyEnums; 51 52 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 53 import com.android.managedprovisioning.common.Utils; 54 import com.android.managedprovisioning.model.ProvisioningParams; 55 import com.android.managedprovisioning.task.AbstractProvisioningTask; 56 import java.util.List; 57 58 /** 59 * Utility class to log metrics. 60 */ 61 public class ProvisioningAnalyticsTracker { 62 63 private final MetricsLoggerWrapper mMetricsLoggerWrapper = new MetricsLoggerWrapper(); 64 65 // Only add to the end of the list. Do not change or rearrange these values, that will break 66 // historical data. Do not use negative numbers or zero, logger only handles positive 67 // integers. 68 public static final int CANCELLED_BEFORE_PROVISIONING = 1; 69 public static final int CANCELLED_DURING_PROVISIONING = 2; 70 public static final int CANCELLED_DURING_PROVISIONING_PREPARE = 3; 71 private final ManagedProvisioningSharedPreferences mSharedPreferences; 72 73 @IntDef({ 74 CANCELLED_BEFORE_PROVISIONING, 75 CANCELLED_DURING_PROVISIONING, 76 CANCELLED_DURING_PROVISIONING_PREPARE}) 77 public @interface CancelState {} 78 79 // Only add to the end of the list. Do not change or rearrange these values, that will break 80 // historical data. Do not use negative numbers or zero, logger only handles positive 81 // integers. 82 public static final int COPY_ACCOUNT_SUCCEEDED = 1; 83 public static final int COPY_ACCOUNT_FAILED = 2; 84 public static final int COPY_ACCOUNT_TIMED_OUT = 3; 85 public static final int COPY_ACCOUNT_EXCEPTION = 4; 86 87 @IntDef({ 88 COPY_ACCOUNT_SUCCEEDED, 89 COPY_ACCOUNT_FAILED, 90 COPY_ACCOUNT_TIMED_OUT, 91 COPY_ACCOUNT_EXCEPTION}) 92 public @interface CopyAccountStatus {} 93 94 private static final int PROVISIONING_FLOW_TYPE_ADMIN_INTEGRATED = 1; 95 private static final int PROVISIONING_FLOW_TYPE_LEGACY = 2; 96 97 private static final int DPC_SETUP_ACTION_UNKNOWN = 1; 98 private static final int DPC_SETUP_ACTION_PROVISIONING_SUCCESSFUL = 2; 99 private static final int DPC_SETUP_ACTION_ADMIN_POLICY_COMPLIANCE = 3; 100 101 private final MetricsWriter mMetricsWriter; 102 ProvisioningAnalyticsTracker(MetricsWriter metricsWriter, ManagedProvisioningSharedPreferences prefs)103 public ProvisioningAnalyticsTracker(MetricsWriter metricsWriter, 104 ManagedProvisioningSharedPreferences prefs) { 105 // Disables instantiation. Use getInstance() instead. 106 mMetricsWriter = metricsWriter; 107 mSharedPreferences = prefs; 108 } 109 110 /** 111 * Logs some metrics when the provisioning starts. 112 * 113 * @param context Context passed to MetricsLogger 114 * @param params Provisioning params 115 */ logProvisioningStarted(Context context, ProvisioningParams params)116 public void logProvisioningStarted(Context context, ProvisioningParams params) { 117 logDpcPackageInformation(context, params.inferDeviceAdminPackageName()); 118 logNetworkType(context); 119 maybeLogProvisioningFlowType(params); 120 } 121 122 /** 123 * Logs some metrics when the preprovisioning starts. 124 * 125 * @param context Context passed to MetricsLogger 126 * @param intent Intent that started provisioning 127 */ logPreProvisioningStarted(Context context, Intent intent)128 public void logPreProvisioningStarted(Context context, Intent intent) { 129 logProvisioningExtras(context, intent); 130 maybeLogEntryPoint(context, intent); 131 } 132 133 /** 134 * Logs status of copy account to user task. 135 * 136 * @param context Context passed to MetricsLogger 137 * @param status Status of copy account to user task 138 */ logCopyAccountStatus(Context context, @CopyAccountStatus int status)139 public void logCopyAccountStatus(Context context, @CopyAccountStatus int status) { 140 mMetricsLoggerWrapper.logAction(context, PROVISIONING_COPY_ACCOUNT_STATUS, status); 141 mMetricsWriter.write(DevicePolicyEventLogger 142 .createEvent(DevicePolicyEnums.PROVISIONING_COPY_ACCOUNT_STATUS) 143 .setInt(status) 144 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 145 } 146 147 /** 148 * Logs when provisioning is cancelled. 149 * 150 * @param context Context passed to MetricsLogger 151 * @param cancelState State when provisioning was cancelled 152 */ logProvisioningCancelled(Context context, @CancelState int cancelState)153 public void logProvisioningCancelled(Context context, @CancelState int cancelState) { 154 mMetricsLoggerWrapper.logAction(context, PROVISIONING_CANCELLED, cancelState); 155 mMetricsWriter.write(DevicePolicyEventLogger 156 .createEvent(DevicePolicyEnums.PROVISIONING_CANCELLED) 157 .setInt(cancelState) 158 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 159 } 160 161 /** 162 * Logs error during provisioning tasks. 163 * 164 * @param context Context passed to MetricsLogger 165 * @param task Provisioning task which threw error 166 * @param errorCode Code indicating the type of error that happened. 167 */ logProvisioningError(Context context, AbstractProvisioningTask task, int errorCode)168 public void logProvisioningError(Context context, AbstractProvisioningTask task, 169 int errorCode) { 170 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR, 171 AnalyticsUtils.getErrorString(task, errorCode)); 172 mMetricsWriter.write(DevicePolicyEventLogger 173 .createEvent(DevicePolicyEnums.PROVISIONING_ERROR) 174 .setStrings(AnalyticsUtils.getErrorString(task, errorCode)) 175 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 176 } 177 178 /** 179 * Logs error code, when provisioning is not allowed. 180 * 181 * @param context Context passed to MetricsLogger 182 * @param provisioningErrorCode Code indicating why provisioning is not allowed. 183 */ logProvisioningNotAllowed(Context context, int provisioningErrorCode)184 public void logProvisioningNotAllowed(Context context, int provisioningErrorCode) { 185 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ERROR, provisioningErrorCode); 186 mMetricsWriter.write(DevicePolicyEventLogger 187 .createEvent(DevicePolicyEnums.PROVISIONING_ERROR) 188 .setStrings(String.valueOf(provisioningErrorCode)) 189 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 190 } 191 192 /** 193 * logs when a provisioning session has started. 194 * 195 * @param context Context passed to MetricsLogger 196 */ logProvisioningSessionStarted(Context context)197 public void logProvisioningSessionStarted(Context context) { 198 mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_STARTED); 199 mMetricsWriter.write(DevicePolicyEventLogger 200 .createEvent(DevicePolicyEnums.PROVISIONING_SESSION_STARTED) 201 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 202 } 203 204 /** 205 * logs when a provisioning session has completed. 206 * 207 * @param context Context passed to MetricsLogger 208 */ logProvisioningSessionCompleted(Context context)209 public void logProvisioningSessionCompleted(Context context) { 210 mMetricsLoggerWrapper.logAction(context, PROVISIONING_SESSION_COMPLETED); 211 mMetricsWriter.write(DevicePolicyEventLogger 212 .createEvent(DevicePolicyEnums.PROVISIONING_SESSION_COMPLETED) 213 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 214 } 215 216 /** 217 * logs number of terms displayed on the terms screen. 218 * 219 * @param context Context passed to MetricsLogger 220 * @param count Number of terms displayed 221 */ logNumberOfTermsDisplayed(Context context, int count)222 public void logNumberOfTermsDisplayed(Context context, int count) { 223 mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_COUNT, count); 224 mMetricsWriter.write(DevicePolicyEventLogger 225 .createEvent(DevicePolicyEnums.PROVISIONING_TERMS_COUNT) 226 .setInt(count) 227 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 228 } 229 230 /** 231 * logs number of terms read on the terms screen. 232 * 233 * @param context Context passed to MetricsLogger 234 * @param count Number of terms read 235 */ logNumberOfTermsRead(Context context, int count)236 public void logNumberOfTermsRead(Context context, int count) { 237 mMetricsLoggerWrapper.logAction(context, PROVISIONING_TERMS_READ, count); 238 mMetricsWriter.write(DevicePolicyEventLogger 239 .createEvent(DevicePolicyEnums.PROVISIONING_TERMS_READ) 240 .setInt(count) 241 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 242 } 243 244 /** 245 * Logs when the provisioning preparation has started. 246 * <p>The preparation includes network setup, downloading, verifying and installing the 247 * admin app. 248 */ logProvisioningPrepareStarted()249 public void logProvisioningPrepareStarted() { 250 mMetricsWriter.write(DevicePolicyEventLogger 251 .createEvent(DevicePolicyEnums.PROVISIONING_PREPARE_STARTED) 252 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 253 } 254 255 /** 256 * Logs when the provisioning preparation has completed. 257 * <p>The preparation includes network setup, downloading, verifying and installing the 258 * admin app. 259 */ logProvisioningPrepareCompleted()260 public void logProvisioningPrepareCompleted() { 261 mMetricsWriter.write(DevicePolicyEventLogger 262 .createEvent(DevicePolicyEnums.PROVISIONING_PREPARE_COMPLETED) 263 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 264 } 265 logTimeLoggerEvent(int devicePolicyEvent, int time)266 public void logTimeLoggerEvent(int devicePolicyEvent, int time) { 267 mMetricsWriter.write(DevicePolicyEventLogger 268 .createEvent(devicePolicyEvent) 269 .setInt(time) 270 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 271 } 272 273 /** 274 * Logs the provisioning action. 275 * @param context Context passed to MetricsLogger 276 * @param provisioningAction Action that triggered provisioning 277 */ logProvisioningAction(Context context, String provisioningAction)278 public void logProvisioningAction(Context context, String provisioningAction) { 279 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ACTION, provisioningAction); 280 mMetricsWriter.write(DevicePolicyEventLogger 281 .createEvent(DevicePolicyEnums.PROVISIONING_ACTION) 282 .setStrings(provisioningAction) 283 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 284 maybeLogManagedProfileOnFullyManagedDevice(context, provisioningAction); 285 } 286 287 /** 288 * Logs organization owned managed profile provisioning. 289 */ logOrganizationOwnedManagedProfileProvisioning()290 public void logOrganizationOwnedManagedProfileProvisioning() { 291 mMetricsWriter.write(DevicePolicyEventLogger 292 .createEvent(DevicePolicyEnums.PROVISIONING_ORGANIZATION_OWNED_MANAGED_PROFILE) 293 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 294 } 295 296 /** 297 * Logs when the DPC is started, for the purpose of enterprise setup. Note that in the admin- 298 * integrated flow, this is when {@link DevicePolicyManager#ACTION_ADMIN_POLICY_COMPLIANCE} is 299 * sent to the DPC, not {@link DevicePolicyManager#ACTION_GET_PROVISIONING_MODE}. 300 * @param context Context passed to MetricsLogger 301 * @param intentAction Action that was sent to the DPC 302 */ logDpcSetupStarted(Context context, String intentAction)303 public void logDpcSetupStarted(Context context, String intentAction) { 304 mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_SETUP_STARTED); 305 306 int intentActionCode; 307 switch(intentAction) { 308 case DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL: 309 intentActionCode = DPC_SETUP_ACTION_PROVISIONING_SUCCESSFUL; 310 break; 311 case DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE: 312 intentActionCode = DPC_SETUP_ACTION_ADMIN_POLICY_COMPLIANCE; 313 break; 314 default: 315 intentActionCode = DPC_SETUP_ACTION_UNKNOWN; 316 break; 317 } 318 319 mMetricsWriter.write(DevicePolicyEventLogger 320 .createEvent(PROVISIONING_DPC_SETUP_STARTED) 321 .setInt(intentActionCode) 322 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 323 } 324 325 /** 326 * Logs when the DPC finishes with enterprise setup. Note that this is only logged when setup 327 * happens inside Setup Wizard; if it happens after Setup Wizard, we never find out when the 328 * DPC finishes. 329 * @param context Context passed to MetricsLogger 330 * @param resultCode The result code that is returned by the DPC 331 */ logDpcSetupCompleted(Context context, int resultCode)332 public void logDpcSetupCompleted(Context context, int resultCode) { 333 mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_SETUP_COMPLETED); 334 mMetricsWriter.write(DevicePolicyEventLogger 335 .createEvent(PROVISIONING_DPC_SETUP_COMPLETED) 336 .setInt(resultCode) 337 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 338 } 339 340 /** 341 * Logs the type of provisioning flow if this is organization owned provisioning. 342 * <p>It would be either admin integrated flow or legacy. 343 * 344 * @param params Used to extract whether this is the admin integrated flow 345 */ maybeLogProvisioningFlowType(ProvisioningParams params)346 private void maybeLogProvisioningFlowType(ProvisioningParams params) { 347 if (!params.isOrganizationOwnedProvisioning) { 348 return; 349 } 350 final boolean isAdminIntegratedFlow = new Utils().isAdminIntegratedFlow(params); 351 mMetricsWriter.write(DevicePolicyEventLogger 352 .createEvent(DevicePolicyEnums.PROVISIONING_FLOW_TYPE) 353 .setInt(isAdminIntegratedFlow 354 ? PROVISIONING_FLOW_TYPE_ADMIN_INTEGRATED 355 : PROVISIONING_FLOW_TYPE_LEGACY) 356 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 357 } 358 359 /** 360 * Logs all the provisioning extras passed by the dpc. 361 * 362 * @param context Context passed to MetricsLogger 363 * @param intent Intent that started provisioning 364 */ logProvisioningExtras(Context context, Intent intent)365 private void logProvisioningExtras(Context context, Intent intent) { 366 final List<String> provisioningExtras = AnalyticsUtils.getAllProvisioningExtras(intent); 367 for (String extra : provisioningExtras) { 368 mMetricsLoggerWrapper.logAction(context, PROVISIONING_EXTRA, extra); 369 } 370 mMetricsWriter.write(DevicePolicyEventLogger 371 .createEvent(DevicePolicyEnums.PROVISIONING_EXTRAS) 372 .setStrings(provisioningExtras.toArray(new String[0])) 373 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 374 } 375 376 /** 377 * Logs some entry points to provisioning. 378 * 379 * @param context Context passed to MetricsLogger 380 * @param intent Intent that started provisioning 381 */ maybeLogEntryPoint(Context context, Intent intent)382 private void maybeLogEntryPoint(Context context, Intent intent) { 383 if (intent == null || intent.getAction() == null) { 384 return; 385 } 386 switch (intent.getAction()) { 387 case ACTION_NDEF_DISCOVERED: 388 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_NFC); 389 mMetricsWriter.write(DevicePolicyEventLogger 390 .createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_NFC) 391 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 392 break; 393 case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE: 394 logProvisionedFromTrustedSource(context, intent); 395 break; 396 } 397 } 398 logProvisionedFromTrustedSource(Context context, Intent intent)399 private void logProvisionedFromTrustedSource(Context context, Intent intent) { 400 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE); 401 final int provisioningTrigger = intent.getIntExtra(EXTRA_PROVISIONING_TRIGGER, 402 PROVISIONING_TRIGGER_UNSPECIFIED); 403 if (provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE) { 404 mMetricsLoggerWrapper.logAction(context, PROVISIONING_ENTRY_POINT_QR_CODE); 405 } 406 mMetricsWriter.write(DevicePolicyEventLogger 407 .createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE) 408 .setInt(provisioningTrigger) 409 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 410 } 411 412 /** 413 * Logs package information of the dpc. 414 * 415 * @param context Context passed to MetricsLogger 416 * @param dpcPackageName Package name of the dpc 417 */ logDpcPackageInformation(Context context, String dpcPackageName)418 private void logDpcPackageInformation(Context context, String dpcPackageName) { 419 // Logs package name of the dpc. 420 mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_PACKAGE_NAME, dpcPackageName); 421 mMetricsWriter.write(DevicePolicyEventLogger 422 .createEvent(DevicePolicyEnums.PROVISIONING_DPC_PACKAGE_NAME) 423 .setStrings(dpcPackageName) 424 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 425 426 // Logs package name of the package which installed dpc. 427 final String dpcInstallerPackage = 428 AnalyticsUtils.getInstallerPackageName(context, dpcPackageName); 429 mMetricsLoggerWrapper.logAction(context, PROVISIONING_DPC_INSTALLED_BY_PACKAGE, 430 dpcInstallerPackage); 431 mMetricsWriter.write(DevicePolicyEventLogger 432 .createEvent(DevicePolicyEnums.PROVISIONING_DPC_INSTALLED_BY_PACKAGE) 433 .setStrings(dpcInstallerPackage) 434 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 435 } 436 437 /** 438 * Logs the network type to which the device is connected. 439 * 440 * @param context Context passed to MetricsLogger 441 */ logNetworkType(Context context)442 private void logNetworkType(Context context) { 443 NetworkTypeLogger networkTypeLogger = new NetworkTypeLogger(context); 444 networkTypeLogger.log(); 445 } 446 maybeLogManagedProfileOnFullyManagedDevice(Context context, String provisioningAction)447 private void maybeLogManagedProfileOnFullyManagedDevice(Context context, 448 String provisioningAction) { 449 final DevicePolicyManager dpm = 450 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 451 final ComponentName currentDeviceOwner = dpm.getDeviceOwnerComponentOnAnyUser(); 452 if (currentDeviceOwner != null 453 && ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningAction)) { 454 mMetricsWriter.write(DevicePolicyEventLogger 455 .createEvent(PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE) 456 .setTimePeriod(AnalyticsUtils.getProvisioningTime(mSharedPreferences))); 457 } 458 } 459 } 460