• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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