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