1 /* 2 * Copyright (C) 2012 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.cts.verifier.managedprovisioning; 18 19 import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES; 20 21 import android.app.KeyguardManager; 22 import android.app.Notification; 23 import android.app.NotificationChannel; 24 import android.app.NotificationManager; 25 import android.app.admin.DevicePolicyManager; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageManager; 30 import android.graphics.Color; 31 import android.net.Uri; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.UserManager; 35 import android.provider.MediaStore; 36 import androidx.core.content.FileProvider; 37 import androidx.core.util.Pair; 38 import android.util.Log; 39 40 import com.android.cts.verifier.R; 41 import com.android.cts.verifier.location.LocationListenerActivity; 42 import com.android.cts.verifier.managedprovisioning.ByodPresentMediaDialog.DialogCallback; 43 44 import java.io.File; 45 import java.util.ArrayList; 46 47 /** 48 * A helper activity from the managed profile side that responds to requests from CTS verifier in 49 * primary user. Profile owner APIs are accessible inside this activity (given this activity is 50 * started within the work profile). Its current functionalities include making sure the profile 51 * owner is setup correctly, removing the work profile upon request, and verifying the image and 52 * video capture functionality. 53 * 54 * Note: We have to use a dummy activity because cross-profile intents only work for activities. 55 */ 56 public class ByodHelperActivity extends LocationListenerActivity 57 implements DialogCallback { 58 static final String TAG = "ByodHelperActivity"; 59 60 // Primary -> managed intent: query if the profile owner has been set up. 61 public static final String ACTION_QUERY_PROFILE_OWNER = "com.android.cts.verifier.managedprovisioning.BYOD_QUERY"; 62 // Managed -> primary intent: update profile owner test status in primary's CtsVerifer 63 public static final String ACTION_PROFILE_OWNER_STATUS = "com.android.cts.verifier.managedprovisioning.BYOD_STATUS"; 64 // Primary -> managed intent: request to delete the current profile 65 public static final String ACTION_REMOVE_MANAGED_PROFILE = "com.android.cts.verifier.managedprovisioning.BYOD_REMOVE"; 66 // Managed -> managed intent: provisioning completed successfully 67 public static final String ACTION_PROFILE_PROVISIONED = "com.android.cts.verifier.managedprovisioning.BYOD_PROVISIONED"; 68 // Primary -> managed intent: request to capture and check an image 69 public static final String ACTION_CAPTURE_AND_CHECK_IMAGE = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_IMAGE"; 70 // Primary -> managed intent: request to capture and check a video with custom output path 71 public static final String ACTION_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT"; 72 // Primary -> managed intent: request to capture and check a video without custom output path 73 public static final String ACTION_CAPTURE_AND_CHECK_VIDEO_WITHOUT_EXTRA_OUTPUT = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO_WITHOUT_EXTRA_OUTPUT"; 74 // Primary -> managed intent: request to capture and check an audio recording 75 public static final String ACTION_CAPTURE_AND_CHECK_AUDIO = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_AUDIO"; 76 public static final String ACTION_KEYGUARD_DISABLED_FEATURES = 77 "com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES"; 78 public static final String ACTION_LOCKNOW = 79 "com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW"; 80 public static final String ACTION_TEST_NFC_BEAM = "com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM"; 81 82 public static final String EXTRA_PROVISIONED = "extra_provisioned"; 83 public static final String EXTRA_PARAMETER_1 = "extra_parameter_1"; 84 85 // Primary -> managed intent: check if the disk of the device is encrypted 86 public static final String ACTION_CHECK_DISK_ENCRYPTION = 87 "com.android.cts.verifier.managedprovisioning.action.BYOD_CHECK_DISK_ENCRYPTION"; 88 // Managed -> primary intent: update disk encryption status in primary's CtsVerifier 89 public static final String ACTION_DISK_ENCRYPTION_STATUS = 90 "com.android.cts.verifier.managedprovisioning.action.BYOD_DISK_ENCRYPTION_STATUS"; 91 // Int extra field indicating the encryption status of the device storage 92 public static final String EXTRA_ENCRYPTION_STATUS = "extra_encryption_status"; 93 94 // Primary -> managed intent: set unknown sources restriction and install package 95 public static final String ACTION_INSTALL_APK = "com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK"; 96 public static final String EXTRA_ALLOW_NON_MARKET_APPS = "allow_non_market_apps"; 97 98 // Primary -> managed intent: check if the required cross profile intent filters are set. 99 public static final String ACTION_CHECK_INTENT_FILTERS = 100 "com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS"; 101 102 // Primary -> managed intent: will send a cross profile intent and check if the user sees an 103 // intent picker dialog and can open the apps. 104 public static final String ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG = 105 "com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG"; 106 107 // Primary -> managed intent: will send an app link intent and check if the user sees a 108 // dialog and can open the apps. This test is extremely similar to 109 // ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG, but the intent used is a web intent, and there is 110 // some behavior which is specific to web intents. 111 public static final String ACTION_TEST_APP_LINKING_DIALOG = 112 "com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG"; 113 114 // Primary -> managed intent: request to goto the location settings page and listen to updates. 115 public static final String ACTION_BYOD_SET_LOCATION_AND_CHECK_UPDATES = 116 "com.android.cts.verifier.managedprovisioning.BYOD_SET_LOCATION_AND_CHECK"; 117 public static final String ACTION_NOTIFICATION = 118 "com.android.cts.verifier.managedprovisioning.NOTIFICATION"; 119 public static final String ACTION_NOTIFICATION_ON_LOCKSCREEN = 120 "com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION"; 121 public static final String ACTION_CLEAR_NOTIFICATION = 122 "com.android.cts.verifier.managedprovisioning.CLEAR_NOTIFICATION"; 123 124 // Primary -> managed intent: set a user restriction 125 public static final String ACTION_SET_USER_RESTRICTION = 126 "com.android.cts.verifier.managedprovisioning.BYOD_SET_USER_RESTRICTION"; 127 128 // Primary -> managed intent: reset a user restriction 129 public static final String ACTION_CLEAR_USER_RESTRICTION = 130 "com.android.cts.verifier.managedprovisioning.BYOD_CLEAR_USER_RESTRICTION"; 131 132 // Primary -> managed intent: Start the selection of a work challenge 133 public static final String ACTION_TEST_SELECT_WORK_CHALLENGE = 134 "com.android.cts.verifier.managedprovisioning.TEST_SELECT_WORK_CHALLENGE"; 135 136 // Primary -> managed intent: Start the selection of a parent profile password. 137 public static final String ACTION_TEST_PARENT_PROFILE_PASSWORD = 138 "com.android.cts.verifier.managedprovisioning.TEST_PARENT_PROFILE_PASSWORD"; 139 140 // Primary -> managed intent: Start the confirm credentials screen for the managed profile 141 public static final String ACTION_LAUNCH_CONFIRM_WORK_CREDENTIALS = 142 "com.android.cts.verifier.managedprovisioning.LAUNCH_CONFIRM_WORK_CREDENTIALS"; 143 144 public static final String ACTION_SET_ORGANIZATION_INFO = 145 "com.android.cts.verifier.managedprovisioning.TEST_ORGANIZATION_INFO"; 146 147 public static final int RESULT_FAILED = RESULT_FIRST_USER; 148 149 private static final int REQUEST_INSTALL_PACKAGE = 2; 150 private static final int REQUEST_IMAGE_CAPTURE = 3; 151 private static final int REQUEST_VIDEO_CAPTURE_WITH_EXTRA_OUTPUT = 4; 152 private static final int REQUEST_VIDEO_CAPTURE_WITHOUT_EXTRA_OUTPUT = 5; 153 private static final int REQUEST_AUDIO_CAPTURE = 6; 154 private static final int REQUEST_LOCATION_UPDATE = 7; 155 156 private static final String ORIGINAL_RESTRICTIONS_NAME = "original restrictions"; 157 158 private static final int NOTIFICATION_ID = 7; 159 private static final String NOTIFICATION_CHANNEL_ID = TAG; 160 161 private NotificationManager mNotificationManager; 162 private Bundle mOriginalRestrictions; 163 164 private ComponentName mAdminReceiverComponent; 165 private DevicePolicyManager mDevicePolicyManager; 166 167 private Uri mImageUri; 168 private Uri mVideoUri; 169 private File mImageFile; 170 171 private ArrayList<File> mTempFiles = new ArrayList<File>(); 172 173 private Handler mMainThreadHandler; 174 175 private void showNotification(int visibility) { 176 final Notification notification = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) 177 .setSmallIcon(R.drawable.icon) 178 .setContentTitle(getString(R.string.provisioning_byod_notification_title)) 179 .setContentText(getString(R.string.provisioning_byod_notification_title)) 180 .setVisibility(visibility) 181 .setAutoCancel(true) 182 .setPublicVersion(createPublicVersionNotification()) 183 .build(); 184 mNotificationManager.notify(NOTIFICATION_ID, notification); 185 } 186 187 private Notification createPublicVersionNotification() { 188 return new Notification.Builder(this) 189 .setSmallIcon(R.drawable.icon) 190 .setContentTitle(getString(R.string.provisioning_byod_notification_public_title)) 191 .setAutoCancel(true) 192 .build(); 193 } 194 195 @Override 196 protected void onCreate(Bundle savedInstanceState) { 197 super.onCreate(savedInstanceState); 198 mMainThreadHandler = new Handler(getMainLooper()); 199 if (savedInstanceState != null) { 200 Log.w(TAG, "Restored state"); 201 mOriginalRestrictions = savedInstanceState.getBundle(ORIGINAL_RESTRICTIONS_NAME); 202 } else { 203 mOriginalRestrictions = new Bundle(); 204 } 205 206 mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName()); 207 mDevicePolicyManager = (DevicePolicyManager) getSystemService( 208 Context.DEVICE_POLICY_SERVICE); 209 mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 210 Intent intent = getIntent(); 211 String action = intent.getAction(); 212 Log.d(TAG, "ByodHelperActivity.onCreate: " + action); 213 mNotificationManager.createNotificationChannel(new NotificationChannel( 214 NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, 215 NotificationManager.IMPORTANCE_DEFAULT)); 216 217 // we are explicitly started by {@link DeviceAdminTestReceiver} after a successful provisioning. 218 if (action.equals(ACTION_PROFILE_PROVISIONED)) { 219 // Jump back to CTS verifier with result. 220 Intent response = new Intent(ACTION_PROFILE_OWNER_STATUS); 221 response.putExtra(EXTRA_PROVISIONED, isProfileOwner()); 222 startActivityInPrimary(response); 223 // Queried by CtsVerifier in the primary side using startActivityForResult. 224 } else if (action.equals(ACTION_QUERY_PROFILE_OWNER)) { 225 Intent response = new Intent(); 226 response.putExtra(EXTRA_PROVISIONED, isProfileOwner()); 227 setResult(RESULT_OK, response); 228 // Request to delete work profile. 229 } else if (action.equals(ACTION_REMOVE_MANAGED_PROFILE)) { 230 if (isProfileOwner()) { 231 Log.d(TAG, "Clearing cross profile intents"); 232 mDevicePolicyManager.clearCrossProfileIntentFilters(mAdminReceiverComponent); 233 mDevicePolicyManager.wipeData(0); 234 showToast(R.string.provisioning_byod_profile_deleted); 235 } 236 } else if (action.equals(ACTION_CHECK_DISK_ENCRYPTION)) { 237 final int status = mDevicePolicyManager.getStorageEncryptionStatus(); 238 final Intent response = new Intent(ACTION_DISK_ENCRYPTION_STATUS) 239 .putExtra(EXTRA_ENCRYPTION_STATUS, status); 240 setResult(RESULT_OK, response); 241 } else if (action.equals(ACTION_INSTALL_APK)) { 242 boolean allowNonMarket = intent.getBooleanExtra(EXTRA_ALLOW_NON_MARKET_APPS, false); 243 boolean wasAllowed = !isUnknownSourcesRestrictionSet(); 244 245 if (wasAllowed != allowNonMarket) { 246 setUnknownSourcesRestriction(!allowNonMarket); 247 mOriginalRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, !wasAllowed); 248 } 249 // Start the installer activity until this activity is rendered to workaround a glitch. 250 mMainThreadHandler.post(() -> { 251 // Request to install a non-market application- easiest way is to reinstall ourself 252 final Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE) 253 .setData(Uri.parse("package:" + getPackageName())) 254 .putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) 255 .putExtra(Intent.EXTRA_RETURN_RESULT, true); 256 startActivityForResult(installIntent, REQUEST_INSTALL_PACKAGE); 257 258 }); 259 // Not yet ready to finish- wait until the result comes back 260 return; 261 // Queried by CtsVerifier in the primary side using startActivityForResult. 262 } else if (action.equals(ACTION_CHECK_INTENT_FILTERS)) { 263 final boolean intentFiltersSetForManagedIntents = 264 new IntentFiltersTestHelper(this).checkCrossProfileIntentFilters( 265 IntentFiltersTestHelper.FLAG_INTENTS_FROM_MANAGED); 266 setResult(intentFiltersSetForManagedIntents? RESULT_OK : RESULT_FAILED, null); 267 } else if (action.equals(ACTION_CAPTURE_AND_CHECK_IMAGE)) { 268 // We need the camera permission to send the image capture intent. 269 grantCameraPermissionToSelf(); 270 Intent captureImageIntent = getCaptureImageIntent(); 271 Pair<File, Uri> pair = getTempUri("image.jpg"); 272 mImageFile = pair.first; 273 mImageUri = pair.second; 274 captureImageIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri); 275 if (captureImageIntent.resolveActivity(getPackageManager()) != null) { 276 startActivityForResult(captureImageIntent, REQUEST_IMAGE_CAPTURE); 277 } else { 278 Log.e(TAG, "Capture image intent could not be resolved in managed profile."); 279 showToast(R.string.provisioning_byod_capture_media_error); 280 finish(); 281 } 282 return; 283 } else if (action.equals(ACTION_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT) || 284 action.equals(ACTION_CAPTURE_AND_CHECK_VIDEO_WITHOUT_EXTRA_OUTPUT)) { 285 // We need the camera permission to send the video capture intent. 286 grantCameraPermissionToSelf(); 287 Intent captureVideoIntent = getCaptureVideoIntent(); 288 int videoCaptureRequestId; 289 if (action.equals(ACTION_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT)) { 290 mVideoUri = getTempUri("video.mp4").second; 291 captureVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mVideoUri); 292 videoCaptureRequestId = REQUEST_VIDEO_CAPTURE_WITH_EXTRA_OUTPUT; 293 } else { 294 videoCaptureRequestId = REQUEST_VIDEO_CAPTURE_WITHOUT_EXTRA_OUTPUT; 295 } 296 if (captureVideoIntent.resolveActivity(getPackageManager()) != null) { 297 startActivityForResult(captureVideoIntent, videoCaptureRequestId); 298 } else { 299 Log.e(TAG, "Capture video intent could not be resolved in managed profile."); 300 showToast(R.string.provisioning_byod_capture_media_error); 301 finish(); 302 } 303 return; 304 } else if (action.equals(ACTION_CAPTURE_AND_CHECK_AUDIO)) { 305 Intent captureAudioIntent = getCaptureAudioIntent(); 306 if (captureAudioIntent.resolveActivity(getPackageManager()) != null) { 307 startActivityForResult(captureAudioIntent, REQUEST_AUDIO_CAPTURE); 308 } else { 309 Log.e(TAG, "Capture audio intent could not be resolved in managed profile."); 310 showToast(R.string.provisioning_byod_capture_media_error); 311 finish(); 312 } 313 return; 314 } else if (ACTION_KEYGUARD_DISABLED_FEATURES.equals(action)) { 315 final int value = intent.getIntExtra(EXTRA_PARAMETER_1, 316 DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE); 317 mDevicePolicyManager.setKeyguardDisabledFeatures(mAdminReceiverComponent, value); 318 } else if (ACTION_LOCKNOW.equals(action)) { 319 mDevicePolicyManager.lockNow(); 320 setResult(RESULT_OK); 321 } else if (action.equals(ACTION_TEST_NFC_BEAM)) { 322 Intent testNfcBeamIntent = new Intent(this, NfcTestActivity.class); 323 testNfcBeamIntent.putExtras(intent); 324 startActivity(testNfcBeamIntent); 325 finish(); 326 return; 327 } else if (action.equals(ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG)) { 328 sendIntentInsideChooser(new Intent( 329 CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL)); 330 } else if (action.equals(ACTION_TEST_APP_LINKING_DIALOG)) { 331 mDevicePolicyManager.addUserRestriction( 332 DeviceAdminTestReceiver.getReceiverComponentName(), 333 UserManager.ALLOW_PARENT_PROFILE_APP_LINKING); 334 Intent toSend = new Intent(Intent.ACTION_VIEW); 335 toSend.setData(Uri.parse("http://com.android.cts.verifier")); 336 sendIntentInsideChooser(toSend); 337 } else if (action.equals(ACTION_SET_USER_RESTRICTION)) { 338 final String restriction = intent.getStringExtra(EXTRA_PARAMETER_1); 339 if (restriction != null) { 340 mDevicePolicyManager.addUserRestriction( 341 DeviceAdminTestReceiver.getReceiverComponentName(), restriction); 342 } 343 } else if (action.equals(ACTION_CLEAR_USER_RESTRICTION)) { 344 final String restriction = intent.getStringExtra(EXTRA_PARAMETER_1); 345 if (restriction != null) { 346 mDevicePolicyManager.clearUserRestriction( 347 DeviceAdminTestReceiver.getReceiverComponentName(), restriction); 348 } 349 } else if (action.equals(ACTION_BYOD_SET_LOCATION_AND_CHECK_UPDATES)) { 350 handleLocationAction(); 351 return; 352 } else if (action.equals(ACTION_NOTIFICATION)) { 353 showNotification(Notification.VISIBILITY_PUBLIC); 354 } else if (ACTION_NOTIFICATION_ON_LOCKSCREEN.equals(action)) { 355 mDevicePolicyManager.lockNow(); 356 showNotification(Notification.VISIBILITY_PRIVATE); 357 } else if (ACTION_CLEAR_NOTIFICATION.equals(action)) { 358 mNotificationManager.cancel(NOTIFICATION_ID); 359 } else if (ACTION_TEST_SELECT_WORK_CHALLENGE.equals(action)) { 360 mDevicePolicyManager.setOrganizationColor(mAdminReceiverComponent, Color.BLUE); 361 mDevicePolicyManager.setOrganizationName(mAdminReceiverComponent, getResources() 362 .getString(R.string.provisioning_byod_confirm_work_credentials_header)); 363 startActivity(new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD)); 364 } else if (ACTION_LAUNCH_CONFIRM_WORK_CREDENTIALS.equals(action)) { 365 KeyguardManager keyguardManager = 366 (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 367 Intent launchIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, null); 368 if (launchIntent != null) { 369 startActivity(launchIntent); 370 } else { 371 showToast(R.string.provisioning_byod_no_secure_lockscreen); 372 } 373 } else if (ACTION_SET_ORGANIZATION_INFO.equals(action)) { 374 if(intent.hasExtra(OrganizationInfoTestActivity.EXTRA_ORGANIZATION_NAME)) { 375 final String organizationName = intent 376 .getStringExtra(OrganizationInfoTestActivity.EXTRA_ORGANIZATION_NAME); 377 mDevicePolicyManager.setOrganizationName(mAdminReceiverComponent, organizationName); 378 } 379 final int organizationColor = intent.getIntExtra( 380 OrganizationInfoTestActivity.EXTRA_ORGANIZATION_COLOR, 381 mDevicePolicyManager.getOrganizationColor(mAdminReceiverComponent)); 382 mDevicePolicyManager.setOrganizationColor(mAdminReceiverComponent, organizationColor); 383 } else if (ACTION_TEST_PARENT_PROFILE_PASSWORD.equals(action)) { 384 startActivity(new Intent(DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD)); 385 } 386 // This activity has no UI and is only used to respond to CtsVerifier in the primary side. 387 finish(); 388 } 389 390 @Override 391 protected void onSaveInstanceState(final Bundle savedState) { 392 super.onSaveInstanceState(savedState); 393 394 savedState.putBundle(ORIGINAL_RESTRICTIONS_NAME, mOriginalRestrictions); 395 } 396 397 @Override 398 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 399 switch (requestCode) { 400 case REQUEST_INSTALL_PACKAGE: { 401 Log.w(TAG, "Received REQUEST_INSTALL_PACKAGE, resultCode = " + resultCode); 402 if (mOriginalRestrictions.containsKey(DISALLOW_INSTALL_UNKNOWN_SOURCES)) { 403 // Restore original setting 404 setUnknownSourcesRestriction( 405 mOriginalRestrictions.getBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES)); 406 mOriginalRestrictions.remove(DISALLOW_INSTALL_UNKNOWN_SOURCES); 407 } 408 finish(); 409 break; 410 } 411 case REQUEST_IMAGE_CAPTURE: { 412 if (resultCode == RESULT_OK) { 413 ByodPresentMediaDialog.newImageInstance(mImageFile) 414 .show(getFragmentManager(), "ViewImageDialogFragment"); 415 } else { 416 // Failed capturing image. 417 finish(); 418 } 419 break; 420 } 421 case REQUEST_VIDEO_CAPTURE_WITH_EXTRA_OUTPUT: { 422 if (resultCode == RESULT_OK) { 423 ByodPresentMediaDialog.newVideoInstance(mVideoUri) 424 .show(getFragmentManager(), "PlayVideoDialogFragment"); 425 } else { 426 // Failed capturing video. 427 finish(); 428 } 429 break; 430 } 431 case REQUEST_VIDEO_CAPTURE_WITHOUT_EXTRA_OUTPUT: { 432 if (resultCode == RESULT_OK) { 433 ByodPresentMediaDialog.newVideoInstance(data.getData()) 434 .show(getFragmentManager(), "PlayVideoDialogFragment"); 435 } else { 436 // Failed capturing video. 437 finish(); 438 } 439 break; 440 } 441 case REQUEST_AUDIO_CAPTURE: { 442 if (resultCode == RESULT_OK) { 443 ByodPresentMediaDialog.newAudioInstance(data.getData()) 444 .show(getFragmentManager(), "PlayAudioDialogFragment"); 445 } else { 446 // Failed capturing audio. 447 finish(); 448 } 449 break; 450 } 451 default: { 452 super.onActivityResult(requestCode, resultCode, data); 453 break; 454 } 455 } 456 } 457 458 @Override 459 protected void onDestroy() { 460 cleanUpTempUris(); 461 super.onDestroy(); 462 } 463 464 public static Intent getCaptureImageIntent() { 465 return new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 466 } 467 468 public static Intent getCaptureVideoIntent() { 469 return new Intent(MediaStore.ACTION_VIDEO_CAPTURE); 470 } 471 472 public static Intent getCaptureAudioIntent() { 473 return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION); 474 } 475 476 public static Intent createLockIntent() { 477 return new Intent(ACTION_LOCKNOW); 478 } 479 480 private Pair<File, Uri> getTempUri(String fileName) { 481 final File file = new File(getFilesDir() + File.separator + "images" 482 + File.separator + fileName); 483 file.getParentFile().mkdirs(); //if the folder doesn't exists it is created 484 mTempFiles.add(file); 485 return new Pair<>(file, FileProvider.getUriForFile(this, 486 "com.android.cts.verifier.managedprovisioning.fileprovider", file)); 487 } 488 489 private void cleanUpTempUris() { 490 for (File file : mTempFiles) { 491 file.delete(); 492 } 493 } 494 495 private boolean isProfileOwner() { 496 return mDevicePolicyManager.isAdminActive(mAdminReceiverComponent) && 497 mDevicePolicyManager.isProfileOwnerApp(mAdminReceiverComponent.getPackageName()); 498 } 499 500 private boolean isUnknownSourcesRestrictionSet() { 501 // We only care about restrictions set by Cts Verifier. In other cases, we cannot modify 502 // it and the test will fail anyway. 503 Bundle restrictions = mDevicePolicyManager.getUserRestrictions(mAdminReceiverComponent); 504 return restrictions.getBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, false); 505 } 506 507 private void setUnknownSourcesRestriction(boolean enabled) { 508 if (enabled) { 509 mDevicePolicyManager.addUserRestriction(mAdminReceiverComponent, 510 DISALLOW_INSTALL_UNKNOWN_SOURCES); 511 } else { 512 mDevicePolicyManager.clearUserRestriction(mAdminReceiverComponent, 513 DISALLOW_INSTALL_UNKNOWN_SOURCES); 514 } 515 } 516 517 private void startActivityInPrimary(Intent intent) { 518 // Disable app components in the current profile, so only the counterpart in the other 519 // profile can respond (via cross-profile intent filter) 520 getPackageManager().setComponentEnabledSetting(new ComponentName( 521 this, ByodFlowTestActivity.class), 522 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 523 PackageManager.DONT_KILL_APP); 524 startActivity(intent); 525 } 526 527 private void grantCameraPermissionToSelf() { 528 mDevicePolicyManager.setPermissionGrantState(mAdminReceiverComponent, getPackageName(), 529 android.Manifest.permission.CAMERA, 530 DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); 531 } 532 533 private void sendIntentInsideChooser(Intent toSend) { 534 toSend.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, true); 535 Intent chooser = Intent.createChooser(toSend, 536 getResources().getString(R.string.provisioning_cross_profile_chooser)); 537 startActivity(chooser); 538 } 539 540 @Override 541 protected void handleLocationAction() { 542 // Grant the locaiton permission to the provile owner on cts-verifier. 543 // The permission state does not have to be reverted at the end since the profile onwer 544 // is going to be deleted when BYOD tests ends. 545 grantLocationPermissionToSelf(); 546 super.handleLocationAction(); 547 } 548 549 private void grantLocationPermissionToSelf() { 550 mDevicePolicyManager.setPermissionGrantState(mAdminReceiverComponent, getPackageName(), 551 android.Manifest.permission.ACCESS_FINE_LOCATION, 552 DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); 553 } 554 555 @Override 556 public void onDialogClose() { 557 finish(); 558 } 559 560 @Override 561 protected String getLogTag() { 562 return TAG; 563 } 564 } 565