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