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 com.android.car.companiondevicesupport.feature.trust.ui; 18 19 import static com.android.car.companiondevicesupport.activity.AssociationActivity.ACTION_ASSOCIATION_SETTING; 20 import static com.android.car.companiondevicesupport.activity.AssociationActivity.ASSOCIATED_DEVICE_DATA_NAME_EXTRA; 21 import static com.android.car.connecteddevice.util.SafeLog.logd; 22 import static com.android.car.connecteddevice.util.SafeLog.loge; 23 import static com.android.car.connecteddevice.util.SafeLog.logw; 24 25 import android.annotation.Nullable; 26 import android.app.AlertDialog; 27 import android.app.Dialog; 28 import android.app.KeyguardManager; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.DialogInterface; 32 import android.content.Intent; 33 import android.content.ServiceConnection; 34 import android.os.Bundle; 35 import android.os.IBinder; 36 import android.os.RemoteException; 37 import android.os.UserHandle; 38 import android.text.Html; 39 import android.text.Spanned; 40 import android.widget.Toast; 41 42 import androidx.fragment.app.DialogFragment; 43 import androidx.fragment.app.FragmentActivity; 44 import androidx.lifecycle.ViewModelProviders; 45 46 import com.android.car.companiondevicesupport.R; 47 import com.android.car.companiondevicesupport.api.external.AssociatedDevice; 48 import com.android.car.companiondevicesupport.api.external.CompanionDevice; 49 import com.android.car.companiondevicesupport.api.external.IDeviceAssociationCallback; 50 import com.android.car.companiondevicesupport.api.internal.trust.ITrustedDeviceEnrollmentCallback; 51 import com.android.car.companiondevicesupport.api.internal.trust.ITrustedDeviceCallback; 52 import com.android.car.companiondevicesupport.api.internal.trust.ITrustedDeviceManager; 53 import com.android.car.companiondevicesupport.api.internal.trust.TrustedDevice; 54 import com.android.car.companiondevicesupport.feature.trust.TrustedDeviceConstants; 55 import com.android.car.companiondevicesupport.feature.trust.TrustedDeviceManagerService; 56 import com.android.car.ui.toolbar.Toolbar; 57 58 import java.util.List; 59 import java.util.concurrent.atomic.AtomicBoolean; 60 61 62 /** Activity for enrolling and viewing trusted devices. */ 63 public class TrustedDeviceActivity extends FragmentActivity { 64 65 private static final String TAG = "TrustedDeviceActivity"; 66 67 private static final int ACTIVATE_TOKEN_REQUEST_CODE = 1; 68 69 private static final int CREATE_LOCK_REQUEST_CODE = 2; 70 71 private static final int RETRIEVE_ASSOCIATED_DEVICE_REQUEST_CODE = 3; 72 73 private static final String ACTION_LOCK_SETTINGS = "android.car.settings.SCREEN_LOCK_ACTIVITY"; 74 75 private static final String DEVICE_DETAIL_FRAGMENT_TAG = "TrustedDeviceDetailFragmentTag"; 76 77 private static final String DEVICE_NOT_CONNECTED_DIALOG_TAG = 78 "DeviceNotConnectedDialogFragmentTag"; 79 80 private static final String CREATE_PROFILE_LOCK_DIALOG_TAG = 81 "CreateProfileLockDialogFragmentTag"; 82 83 private static final String UNLOCK_PROFILE_TO_FINISH_DIALOG_TAG = 84 "UnlockProfileToFinishDialogFragmentTag"; 85 86 private static final String CREATE_PHONE_LOCK_DIALOG_TAG = "CreatePhoneLockDialogFragmentTag"; 87 88 private static final String ENROLLMENT_ERROR_DIALOG_TAG = "EnrollmentErrorDialogFragmentTag"; 89 90 /** {@code true} if a PIN/Pattern/Password has just been set as a screen lock. */ 91 private final AtomicBoolean mIsScreenLockNewlyCreated = new AtomicBoolean(false); 92 93 private final AtomicBoolean mIsStartedForEnrollment = new AtomicBoolean(false); 94 95 private final AtomicBoolean mHasPendingCredential = new AtomicBoolean(false); 96 97 /** 98 * {@code true} if this activity is relaunched for enrollment and the activity needs to be 99 * finished after enrollment has completed. 100 */ 101 private final AtomicBoolean mWasRelaunched = new AtomicBoolean(false); 102 103 private KeyguardManager mKeyguardManager; 104 105 private ITrustedDeviceManager mTrustedDeviceManager; 106 107 private Toolbar mToolbar; 108 109 private TrustedDeviceViewModel mModel; 110 111 @Override onCreate(Bundle savedInstanceState)112 protected void onCreate(Bundle savedInstanceState) { 113 super.onCreate(savedInstanceState); 114 setContentView(R.layout.base_activity); 115 observeViewModel(); 116 resumePreviousState(savedInstanceState); 117 mToolbar = findViewById(R.id.toolbar); 118 mToolbar.setTitle(R.string.trusted_device_feature_title); 119 mToolbar.showProgressBar(); 120 mIsScreenLockNewlyCreated.set(false); 121 mIsStartedForEnrollment.set(false); 122 mHasPendingCredential.set(false); 123 mWasRelaunched.set(false); 124 Intent intent = new Intent(this, TrustedDeviceManagerService.class); 125 bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); 126 } 127 128 @Override onActivityResult(int requestCode, int resultCode, Intent data)129 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 130 super.onActivityResult(requestCode, resultCode, data); 131 132 switch (requestCode) { 133 case ACTIVATE_TOKEN_REQUEST_CODE: 134 if (resultCode != RESULT_OK) { 135 loge(TAG, "Lock screen was unsuccessful. Returned result code: " + 136 resultCode + "."); 137 finishEnrollment(); 138 return; 139 } 140 logd(TAG, "Credentials accepted. Waiting for TrustAgent to activate " + 141 "token."); 142 break; 143 case CREATE_LOCK_REQUEST_CODE: 144 if (!isDeviceSecure()) { 145 loge(TAG, "Set up new lock unsuccessful. Returned result code: " 146 + resultCode + "."); 147 mIsScreenLockNewlyCreated.set(false); 148 return; 149 } 150 151 if (mHasPendingCredential.get()) { 152 showUnlockProfileDialogFragment(); 153 } 154 break; 155 case RETRIEVE_ASSOCIATED_DEVICE_REQUEST_CODE: 156 AssociatedDevice device = data.getParcelableExtra(ASSOCIATED_DEVICE_DATA_NAME_EXTRA); 157 if (device == null) { 158 loge(TAG, "No valid associated device."); 159 return; 160 } 161 mModel.setAssociatedDevice(device); 162 Intent incomingIntent = getIntent(); 163 if (isStartedForEnrollment(incomingIntent)) { 164 processEnrollment(); 165 return; 166 } 167 showTrustedDeviceDetailFragment(device); 168 break; 169 default: 170 logw(TAG, "Unrecognized activity result. Request code: " + requestCode 171 + ". Ignoring."); 172 break; 173 } 174 } 175 176 @Override onNewIntent(Intent intent)177 protected void onNewIntent(Intent intent) { 178 super.onNewIntent(intent); 179 mWasRelaunched.set(true); 180 if (isStartedForEnrollment(intent)) { 181 processEnrollment(); 182 } 183 } 184 185 @Override onDestroy()186 protected void onDestroy() { 187 try { 188 unregisterCallbacks(); 189 } catch (RemoteException e) { 190 loge(TAG, "Error while disconnecting from service.", e); 191 } 192 unbindService(mServiceConnection); 193 super.onDestroy(); 194 } 195 resumePreviousState(Bundle saveInstanceState)196 private void resumePreviousState(Bundle saveInstanceState) { 197 if (saveInstanceState == null) { 198 return; 199 } 200 CreateProfileLockDialogFragment createProfileLockDialogFragment = 201 (CreateProfileLockDialogFragment) getSupportFragmentManager() 202 .findFragmentByTag(CREATE_PROFILE_LOCK_DIALOG_TAG); 203 if (createProfileLockDialogFragment != null) { 204 createProfileLockDialogFragment.setOnConfirmListener((d, w) -> createScreenLock()); 205 } 206 207 UnlockProfileDialogFragment unlockProfileDialogFragment = 208 (UnlockProfileDialogFragment) getSupportFragmentManager() 209 .findFragmentByTag(UNLOCK_PROFILE_TO_FINISH_DIALOG_TAG); 210 if (unlockProfileDialogFragment != null) { 211 unlockProfileDialogFragment.setOnConfirmListener((d, w) -> validateCredentials()); 212 } 213 } 214 observeViewModel()215 private void observeViewModel() { 216 mModel = ViewModelProviders.of(this).get(TrustedDeviceViewModel.class); 217 mModel.getDeviceToDisable().observe(this, trustedDevice -> { 218 if (trustedDevice == null) { 219 return; 220 } 221 mModel.setDeviceToDisable(null); 222 if (mTrustedDeviceManager == null) { 223 loge(TAG, "Failed to remove trusted device. service not connected."); 224 return; 225 } 226 try { 227 logd(TAG, "calling removeTrustedDevice"); 228 mTrustedDeviceManager.removeTrustedDevice(trustedDevice); 229 } catch (RemoteException e) { 230 loge(TAG, "Failed to remove trusted device.", e); 231 } 232 }); 233 mModel.getDeviceToEnable().observe(this, associatedDevice -> { 234 if (associatedDevice == null) { 235 return; 236 } 237 mModel.setDeviceToEnable(null); 238 attemptInitiatingEnrollment(associatedDevice); 239 }); 240 } 241 hasAssociatedDevice()242 private boolean hasAssociatedDevice() { 243 Intent intent = getIntent(); 244 String action = intent.getAction(); 245 if (!TrustedDeviceConstants.INTENT_ACTION_TRUSTED_DEVICE_SETTING.equals(action)) { 246 return false; 247 } 248 AssociatedDevice device = intent.getParcelableExtra(ASSOCIATED_DEVICE_DATA_NAME_EXTRA); 249 if (device == null) { 250 loge(TAG, "No valid associated device."); 251 return false; 252 } 253 mModel.setAssociatedDevice(device); 254 showTrustedDeviceDetailFragment(device); 255 return true; 256 } 257 attemptInitiatingEnrollment(AssociatedDevice device)258 private void attemptInitiatingEnrollment(AssociatedDevice device) { 259 if (!isCompanionDeviceConnected(device.getDeviceId())) { 260 DeviceNotConnectedDialogFragment fragment = new DeviceNotConnectedDialogFragment(); 261 fragment.show(getSupportFragmentManager(), DEVICE_NOT_CONNECTED_DIALOG_TAG); 262 return; 263 } 264 try { 265 mTrustedDeviceManager.initiateEnrollment(device.getDeviceId()); 266 } catch (RemoteException e) { 267 loge(TAG, "Failed to initiate enrollment. ", e); 268 } 269 } 270 isCompanionDeviceConnected(String deviceId)271 private boolean isCompanionDeviceConnected(String deviceId) { 272 if (mTrustedDeviceManager == null) { 273 loge(TAG, "Failed to check connection status for device: " + deviceId + 274 "Service not connected."); 275 return false; 276 } 277 List<CompanionDevice> devices = null; 278 try { 279 devices = mTrustedDeviceManager.getActiveUserConnectedDevices(); 280 } catch (RemoteException e) { 281 loge(TAG, "Failed to check connection status for device: " + deviceId, e); 282 return false; 283 } 284 if (devices == null || devices.isEmpty()) { 285 return false; 286 } 287 for (CompanionDevice device: devices) { 288 if (device.getDeviceId().equals(deviceId)) { 289 return true; 290 } 291 } 292 return false; 293 } 294 validateCredentials()295 private void validateCredentials() { 296 logd(TAG, "Validating credentials to activate token."); 297 KeyguardManager keyguardManager = getKeyguardManager(); 298 if (keyguardManager == null) { 299 return; 300 } 301 if (!mIsStartedForEnrollment.get()) { 302 mHasPendingCredential.set(true); 303 return; 304 } 305 if (mIsScreenLockNewlyCreated.get()) { 306 showUnlockProfileDialogFragment(); 307 return; 308 } 309 @SuppressWarnings("deprecation") // Car does not support Biometric lock as of now. 310 Intent confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent( 311 "PLACEHOLDER PROMPT TITLE", "PLACEHOLDER PROMPT MESSAGE"); 312 if (confirmIntent == null) { 313 loge(TAG, "User either has no lock screen, or a token is already registered."); 314 return; 315 } 316 mHasPendingCredential.set(false); 317 mIsStartedForEnrollment.set(false); 318 logd(TAG, "Prompting user to validate credentials."); 319 startActivityForResult(confirmIntent, ACTIVATE_TOKEN_REQUEST_CODE); 320 } 321 processEnrollment()322 private void processEnrollment() { 323 mIsStartedForEnrollment.set(true); 324 if (mHasPendingCredential.get()) { 325 validateCredentials(); 326 return; 327 } 328 maybePromptToCreatePassword(); 329 } 330 isStartedForEnrollment(Intent intent)331 private boolean isStartedForEnrollment(Intent intent) { 332 return intent != null && intent.getBooleanExtra( 333 TrustedDeviceConstants.INTENT_EXTRA_ENROLL_NEW_TOKEN, false); 334 } 335 finishEnrollment()336 private void finishEnrollment() { 337 if (!mWasRelaunched.get()) { 338 // If the activity is not relaunched for enrollment, it needs to be finished to make the 339 // foreground return to the previous screen. 340 finish(); 341 } 342 } 343 maybePromptToCreatePassword()344 private void maybePromptToCreatePassword() { 345 if (isDeviceSecure()) { 346 return; 347 } 348 349 CreateProfileLockDialogFragment fragment = CreateProfileLockDialogFragment.newInstance( 350 (d, w) -> createScreenLock()); 351 fragment.show(getSupportFragmentManager(), CREATE_PROFILE_LOCK_DIALOG_TAG); 352 } 353 createScreenLock()354 private void createScreenLock() { 355 if (isDeviceSecure()) { 356 return; 357 } 358 logd(TAG, "User has not set a lock screen. Redirecting to set up."); 359 Intent intent = new Intent(ACTION_LOCK_SETTINGS); 360 mIsScreenLockNewlyCreated.set(true); 361 startActivityForResult(intent, CREATE_LOCK_REQUEST_CODE); 362 } 363 isDeviceSecure()364 private boolean isDeviceSecure() { 365 KeyguardManager keyguardManager = getKeyguardManager(); 366 if (keyguardManager == null) { 367 return false; 368 } 369 return keyguardManager.isDeviceSecure(); 370 } 371 retrieveAssociatedDevice()372 private void retrieveAssociatedDevice() { 373 Intent intent = new Intent(ACTION_ASSOCIATION_SETTING); 374 startActivityForResult(intent, RETRIEVE_ASSOCIATED_DEVICE_REQUEST_CODE); 375 } 376 showTrustedDeviceDetailFragment(AssociatedDevice device)377 private void showTrustedDeviceDetailFragment(AssociatedDevice device) { 378 mToolbar.hideProgressBar(); 379 TrustedDeviceDetailFragment fragment = TrustedDeviceDetailFragment.newInstance(device); 380 getSupportFragmentManager().beginTransaction() 381 .replace(R.id.fragment_container, fragment, DEVICE_DETAIL_FRAGMENT_TAG) 382 .commit(); 383 } 384 showUnlockProfileDialogFragment()385 private void showUnlockProfileDialogFragment() { 386 mIsScreenLockNewlyCreated.set(false); 387 UnlockProfileDialogFragment fragment = UnlockProfileDialogFragment.newInstance((d, w) -> 388 validateCredentials()); 389 fragment.show(getSupportFragmentManager(), UNLOCK_PROFILE_TO_FINISH_DIALOG_TAG); 390 } 391 showEnrollmentSuccessToast(TrustedDevice device)392 private void showEnrollmentSuccessToast(TrustedDevice device) { 393 AssociatedDevice addedDevice = mModel.getAssociatedDevice().getValue(); 394 if (addedDevice == null) { 395 loge(TAG, "No associated device retrieved when a trusted device has been added."); 396 return; 397 } 398 if (!addedDevice.getDeviceId().equals(device.getDeviceId())) { 399 loge(TAG, "Id of the enrolled trusted device doesn't match id of the current device"); 400 return; 401 } 402 String message = getString(R.string.trusted_device_enrollment_success_message, 403 addedDevice.getDeviceName()); 404 Spanned styledMessage = Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY); 405 runOnUiThread(() -> 406 Toast.makeText(getApplicationContext(), styledMessage, Toast.LENGTH_SHORT).show()); 407 } 408 showEnrollmentErrorDialogFragment(int error)409 private void showEnrollmentErrorDialogFragment(int error) { 410 switch (error) { 411 case TrustedDeviceConstants.TRUSTED_DEVICE_ERROR_DEVICE_NOT_SECURED: 412 CreatePhoneLockDialogFragment createPhoneLockDialogFragment = 413 new CreatePhoneLockDialogFragment(); 414 createPhoneLockDialogFragment.show(getSupportFragmentManager(), 415 CREATE_PHONE_LOCK_DIALOG_TAG); 416 break; 417 case TrustedDeviceConstants.TRUSTED_DEVICE_ERROR_MESSAGE_TYPE_UNKNOWN: 418 case TrustedDeviceConstants.TRUSTED_DEVICE_ERROR_UNKNOWN: 419 EnrollmentErrorDialogFragment enrollmentErrorDialogFragment = 420 new EnrollmentErrorDialogFragment(); 421 enrollmentErrorDialogFragment.show(getSupportFragmentManager(), 422 ENROLLMENT_ERROR_DIALOG_TAG); 423 break; 424 default: 425 loge(TAG, "Encountered unexpected error: " + error + "."); 426 } 427 } 428 registerCallbacks()429 private void registerCallbacks() throws RemoteException { 430 if (mTrustedDeviceManager == null) { 431 loge(TAG, "Server not connected when attempting to register callbacks."); 432 return; 433 } 434 mTrustedDeviceManager.registerTrustedDeviceEnrollmentCallback( 435 mTrustedDeviceEnrollmentCallback); 436 mTrustedDeviceManager.registerTrustedDeviceCallback(mTrustedDeviceCallback); 437 mTrustedDeviceManager.registerAssociatedDeviceCallback(mDeviceAssociationCallback); 438 } 439 unregisterCallbacks()440 private void unregisterCallbacks() throws RemoteException { 441 if (mTrustedDeviceManager == null) { 442 loge(TAG, "Server not connected when attempting to unregister callbacks."); 443 return; 444 } 445 mTrustedDeviceManager.unregisterTrustedDeviceEnrollmentCallback( 446 mTrustedDeviceEnrollmentCallback); 447 mTrustedDeviceManager.unregisterTrustedDeviceCallback(mTrustedDeviceCallback); 448 mTrustedDeviceManager.unregisterAssociatedDeviceCallback(mDeviceAssociationCallback); 449 } 450 451 private final ServiceConnection mServiceConnection = new ServiceConnection() { 452 @Override 453 public void onServiceConnected(ComponentName name, IBinder service) { 454 mTrustedDeviceManager = ITrustedDeviceManager.Stub.asInterface(service); 455 try { 456 registerCallbacks(); 457 mModel.setTrustedDevices(mTrustedDeviceManager.getTrustedDevicesForActiveUser()); 458 } catch (RemoteException e) { 459 loge(TAG, "Error while connecting to service."); 460 } 461 462 logd(TAG, "Successfully connected to TrustedDeviceManager."); 463 464 if (!hasAssociatedDevice()) { 465 retrieveAssociatedDevice(); 466 } 467 } 468 469 @Override 470 public void onServiceDisconnected(ComponentName name) { 471 } 472 }; 473 474 private final ITrustedDeviceCallback mTrustedDeviceCallback = 475 new ITrustedDeviceCallback.Stub() { 476 @Override 477 public void onTrustedDeviceAdded(TrustedDevice device) { 478 logd(TAG, "Added trusted device: " + device + "."); 479 mModel.setEnabledDevice(device); 480 showEnrollmentSuccessToast(device); 481 finishEnrollment(); 482 } 483 484 @Override 485 public void onTrustedDeviceRemoved(TrustedDevice device) { 486 logd(TAG, "Removed trusted device: " + device +"."); 487 mModel.setDisabledDevice(device); 488 } 489 }; 490 491 private final IDeviceAssociationCallback mDeviceAssociationCallback = 492 new IDeviceAssociationCallback.Stub() { 493 @Override 494 public void onAssociatedDeviceAdded(AssociatedDevice device) { } 495 496 @Override 497 public void onAssociatedDeviceRemoved(AssociatedDevice device) { 498 AssociatedDevice currentDevice = mModel.getAssociatedDevice().getValue(); 499 if (device.equals(currentDevice)) { 500 finish(); 501 } 502 } 503 504 @Override 505 public void onAssociatedDeviceUpdated(AssociatedDevice device) { 506 if (device != null) { 507 mModel.setAssociatedDevice(device); 508 } 509 } 510 }; 511 512 @Nullable getKeyguardManager()513 private KeyguardManager getKeyguardManager() { 514 if (mKeyguardManager == null) { 515 mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 516 } 517 if (mKeyguardManager == null) { 518 loge(TAG, "Unable to get KeyguardManager."); 519 } 520 return mKeyguardManager; 521 } 522 523 private ITrustedDeviceEnrollmentCallback mTrustedDeviceEnrollmentCallback = 524 new ITrustedDeviceEnrollmentCallback.Stub() { 525 526 @Override 527 public void onValidateCredentialsRequest() { 528 validateCredentials(); 529 } 530 531 @Override 532 public void onTrustedDeviceEnrollmentError(int error) { 533 loge(TAG, "Failed to enroll trusted device, encountered error: " + error + "."); 534 showEnrollmentErrorDialogFragment(error); 535 } 536 }; 537 538 /** Dialog Fragment to notify that the device is not actively connected. */ 539 public static class DeviceNotConnectedDialogFragment extends DialogFragment { 540 @Override onCreateDialog(Bundle savedInstanceState)541 public Dialog onCreateDialog(Bundle savedInstanceState) { 542 return new AlertDialog.Builder(getActivity()) 543 .setTitle(getString(R.string.device_not_connected_dialog_title)) 544 .setMessage(getString(R.string.device_not_connected_dialog_message)) 545 .setNegativeButton(getString(R.string.ok), null) 546 .setCancelable(true) 547 .create(); 548 } 549 } 550 551 /** Dialog Fragment to notify that a profile lock is needed to continue enrollment. */ 552 public static class CreateProfileLockDialogFragment extends DialogFragment { 553 private DialogInterface.OnClickListener mOnConfirmListener; 554 newInstance( DialogInterface.OnClickListener listener)555 static CreateProfileLockDialogFragment newInstance( 556 DialogInterface.OnClickListener listener) { 557 CreateProfileLockDialogFragment fragment = new CreateProfileLockDialogFragment(); 558 fragment.setOnConfirmListener(listener); 559 return fragment; 560 } 561 562 @Override onCreateDialog(Bundle savedInstanceState)563 public Dialog onCreateDialog(Bundle savedInstanceState) { 564 return new AlertDialog.Builder(getActivity()) 565 .setTitle(getString(R.string.create_profile_lock_dialog_title)) 566 .setMessage(getString(R.string.create_profile_lock_dialog_message)) 567 .setNegativeButton(getString(R.string.cancel), null) 568 .setPositiveButton(getString(R.string.continue_button), mOnConfirmListener) 569 .setCancelable(true) 570 .create(); 571 } 572 setOnConfirmListener(DialogInterface.OnClickListener onConfirmListener)573 void setOnConfirmListener(DialogInterface.OnClickListener onConfirmListener) { 574 mOnConfirmListener = onConfirmListener; 575 } 576 } 577 578 /** Dialog Fragment to notify that the user needs to unlock again to finish enrollment. */ 579 public static class UnlockProfileDialogFragment extends DialogFragment { 580 private DialogInterface.OnClickListener mOnConfirmListener; 581 newInstance(DialogInterface.OnClickListener listener)582 static UnlockProfileDialogFragment newInstance(DialogInterface.OnClickListener listener) { 583 UnlockProfileDialogFragment fragment = new UnlockProfileDialogFragment(); 584 fragment.setOnConfirmListener(listener); 585 return fragment; 586 } 587 588 @Override onCreateDialog(Bundle savedInstanceState)589 public Dialog onCreateDialog(Bundle savedInstanceState) { 590 return new AlertDialog.Builder(getActivity()) 591 .setTitle(getString(R.string.unlock_profile_to_finish_title)) 592 .setMessage(getString(R.string.unlock_profile_to_finish_message)) 593 .setNegativeButton(getString(R.string.cancel), null) 594 .setPositiveButton(getString(R.string.continue_button), mOnConfirmListener) 595 .setCancelable(true) 596 .create(); 597 } 598 setOnConfirmListener(DialogInterface.OnClickListener onConfirmListener)599 void setOnConfirmListener(DialogInterface.OnClickListener onConfirmListener) { 600 mOnConfirmListener = onConfirmListener; 601 } 602 } 603 604 /** Dialog Fragment to notify that the user needs to set up phone unlock before enrollment.*/ 605 public static class CreatePhoneLockDialogFragment extends DialogFragment { 606 @Override onCreateDialog(Bundle savedInstanceState)607 public Dialog onCreateDialog(Bundle savedInstanceState) { 608 return new AlertDialog.Builder(getActivity()) 609 .setTitle(getString(R.string.create_phone_lock_dialog_title)) 610 .setMessage(getString(R.string.create_phone_lock_dialog_message)) 611 .setPositiveButton(getString(R.string.ok), null) 612 .setCancelable(true) 613 .create(); 614 } 615 } 616 617 /** Dialog Fragment to notify error during enrollment.*/ 618 public static class EnrollmentErrorDialogFragment extends DialogFragment { 619 @Override onCreateDialog(Bundle savedInstanceState)620 public Dialog onCreateDialog(Bundle savedInstanceState) { 621 return new AlertDialog.Builder(getActivity()) 622 .setTitle(getString(R.string.trusted_device_enrollment_error_dialog_title)) 623 .setMessage(getString(R.string.trusted_device_enrollment_error_dialog_message)) 624 .setPositiveButton(getString(R.string.ok), null) 625 .setCancelable(true) 626 .create(); 627 } 628 } 629 } 630