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.content.Intent.FLAG_ACTIVITY_NEW_TASK;
20 
21 import android.app.KeyguardManager;
22 import android.app.admin.DevicePolicyManager;
23 import android.content.ActivityNotFoundException;
24 import android.content.BroadcastReceiver;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.SharedPreferences;
29 import android.content.pm.PackageManager;
30 import android.net.ConnectivityManager;
31 import android.os.Bundle;
32 import android.os.Handler;
33 import android.os.Looper;
34 import android.provider.Settings;
35 import android.util.Log;
36 import android.widget.Toast;
37 
38 import com.android.cts.verifier.ArrayTestListAdapter;
39 import com.android.cts.verifier.DialogTestListActivity;
40 import com.android.cts.verifier.R;
41 import com.android.cts.verifier.TestListActivity;
42 import com.android.cts.verifier.TestListAdapter.TestListItem;
43 import com.android.cts.verifier.TestResult;
44 
45 /**
46  * CTS verifier test for BYOD managed provisioning flow
47  *
48  * This activity is responsible for starting the managed provisioning flow and verify the outcome of
49  * provisioning. It performs the following verifications:
50  *   Full disk encryption is enabled.
51  *   Profile owner is correctly installed.
52  *   Profile owner shows up in the Settings app.
53  *   Badged work apps show up in launcher.
54  * The first two verifications are performed automatically, by interacting with profile owner using
55  * cross-profile intents, while the last two are carried out manually by the user.
56  */
57 public class ByodFlowTestActivity extends DialogTestListActivity {
58 
59     // Action for delivering sub-test result from the profile.
60     public static final String ACTION_TEST_RESULT =
61             "com.android.cts.verifier.managedprovisioning.BYOD_TEST_RESULT";
62     // Extra for ACTION_TEST_RESULT containing test result.
63     public static final String EXTRA_RESULT = "extra-result";
64     protected static final String HELPER_APP_PATH = "/data/local/tmp/NotificationBot.apk";
65 
66     private static final String TAG = "ByodFlowTestActivity";
67     private static final int PROVISIONING_CHECK_PERIOD_MS = 3000;
68     private static ConnectivityManager mCm;
69     private static final int REQUEST_MANAGED_PROVISIONING = 0;
70     private static final int REQUEST_PROFILE_OWNER_STATUS = 1;
71     private static final int REQUEST_INTENT_FILTERS_STATUS = 2;
72     private static final int REQUEST_CHECK_DISK_ENCRYPTION = 3;
73     private static final int REQUEST_SET_LOCK_FOR_ENCRYPTION = 4;
74     private static final int REQUEST_DELETE_MANAGED_PROFILE = 5;
75 
76     private static final String PROVISIONING_PREFERENCES = "provisioning_preferences";
77     private static final String PREFERENCE_PROVISIONING_COMPLETE_STATUS =
78             "provisioning_complete_status";
79     private static final int PREFERENCE_PROVISIONING_COMPLETE_STATUS_NOT_RECEIVED = 0;
80     private static final int PREFERENCE_PROVISIONING_COMPLETE_STATUS_RECEIVED = 1;
81     private static final int PREFERENCE_PROVISIONING_COMPLETE_STATUS_PROCESSED = 2;
82 
83     private ComponentName mAdminReceiverComponent;
84     private KeyguardManager mKeyguardManager;
85     private ByodFlowTestHelper mByodFlowTestHelper;
86 
87     private DialogTestListItem mProfileOwnerInstalled;
88     private DialogTestListItem mDiskEncryptionTest;
89     private DialogTestListItem mWorkAppVisibleTest;
90     private DialogTestListItem mCrossProfileIntentFiltersTestFromPersonal;
91     private DialogTestListItem mCrossProfileIntentFiltersTestFromWork;
92     private TestListItem mCrossProfilePermissionControl;
93     private TestListItem mNonMarketAppsTest;
94     private DialogTestListItem mUserSettingsVisibleTest;
95     private DialogTestListItem mAppSettingsVisibleTest;
96     private DialogTestListItem mLocationSettingsVisibleTest;
97     private DialogTestListItem mWiFiDataUsageSettingsVisibleTest;
98     private DialogTestListItem mCellularDataUsageSettingsVisibleTest;
99     private DialogTestListItem mCredSettingsVisibleTest;
100     private DialogTestListItem mAllowNonDismissibleNotificationTest;
101     private DialogTestListItem mPrintSettingsVisibleTest;
102     private DialogTestListItem mIntentFiltersTest;
103     private DialogTestListItem mPermissionLockdownTest;
104     private DialogTestListItem mCrossProfileImageCaptureSupportTest;
105     private DialogTestListItem mCrossProfileVideoCaptureWithExtraOutputSupportTest;
106     private DialogTestListItem mCrossProfileVideoCaptureWithoutExtraOutputSupportTest;
107     private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
108     private TestListItem mKeyguardDisabledFeaturesTest;
109     private TestListItem mAuthenticationBoundKeyTest;
110     private TestListItem mEnableLocationModeTest;
111     private TestListItem mDisableLocationModeThroughMainSwitchTest;
112     private TestListItem mDisableLocationModeThroughWorkSwitchTest;
113     private TestListItem mPrimaryLocationWhenWorkDisabledTest;
114     private DialogTestListItem mSelectWorkChallenge;
115     private DialogTestListItem mConfirmWorkCredentials;
116     private DialogTestListItem mPatternWorkChallenge;
117     private DialogTestListItem mParentProfilePassword;
118     private DialogTestListItem mPersonalRingtonesTest;
119     private TestListItem mScreenshotTest;
120     private TestListItem mVpnTest;
121     private TestListItem mKeyChainTest;
122     private TestListItem mAlwaysOnVpnSettingsTest;
123     private TestListItem mRecentsTest;
124     private TestListItem mDisallowAppsControlTest;
125     private TestListItem mOrganizationInfoTest;
126     private TestListItem mPolicyTransparencyTest;
127     private TestListItem mTurnOffWorkFeaturesTest;
128     private TestListItem mWidgetTest;
129     private final Handler mHandler = new Handler(Looper.myLooper());
130 
131     private final Runnable mPeriodicProvisioningCheckRunnable = new Runnable() {
132         @Override
133         public void run() {
134             if (isProvisioningCompleteBroadcastReceived(getApplicationContext())) {
135                 markProvisioningCompleteBroadcastProcessed(getApplicationContext());
136                 queryProfileOwner(true);
137             } else {
138                 mHandler.postDelayed(this, PROVISIONING_CHECK_PERIOD_MS);
139             }
140         }
141     };
142 
143     public static class ProvisioningCompleteReceiver extends BroadcastReceiver {
144         @Override
onReceive(Context context, Intent intent)145         public void onReceive(Context context, Intent intent) {
146             markProvisioningCompleteBroadcastReceived(context);
147         }
148     }
149 
ByodFlowTestActivity()150     public ByodFlowTestActivity() {
151         super(R.layout.provisioning_byod,
152                 R.string.provisioning_byod, R.string.provisioning_byod_info,
153                 R.string.provisioning_byod_instructions);
154     }
155 
156     @Override
onCreate(Bundle savedInstanceState)157     protected void onCreate(Bundle savedInstanceState) {
158         super.onCreate(savedInstanceState);
159         mByodFlowTestHelper = new ByodFlowTestHelper(this);
160         mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
161         mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
162 
163         mByodFlowTestHelper.setup();
164 
165         mPrepareTestButton.setText(R.string.provisioning_byod_start);
166         mPrepareTestButton.setOnClickListener(v -> Utils.provisionManagedProfile(
167                 ByodFlowTestActivity.this, mAdminReceiverComponent,
168                 REQUEST_MANAGED_PROVISIONING));
169 
170         // If we are started by managed provisioning (fresh managed provisioning after encryption
171         // reboot), redirect the user back to the main test list. This is because the test result
172         // is only saved by the parent TestListActivity, and if we did allow the user to proceed
173         // here, the test result would be lost when this activity finishes.
174         if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(getIntent().getAction())) {
175             startActivity(new Intent(this, TestListActivity.class));
176             // Calling super.finish() because we delete managed profile in our overridden of finish(),
177             // which is not what we want to do here.
178             super.finish();
179         } else {
180             queryProfileOwner(false);
181         }
182     }
183 
184     @Override
onStart()185     protected void onStart() {
186         super.onStart();
187         startPeriodicProvisioningCheckIfNecessary();
188     }
189 
startPeriodicProvisioningCheckIfNecessary()190     private void startPeriodicProvisioningCheckIfNecessary() {
191         if (mHandler.hasCallbacks(mPeriodicProvisioningCheckRunnable)) {
192             return;
193         }
194         if (!isProvisioningCompleteBroadcastProcessed(this)) {
195             mHandler.post(mPeriodicProvisioningCheckRunnable);
196         }
197     }
198 
199     @Override
onStop()200     protected void onStop() {
201         super.onStop();
202         mHandler.removeCallbacks(mPeriodicProvisioningCheckRunnable);
203     }
204 
205     @Override
onNewIntent(Intent intent)206     protected void onNewIntent(Intent intent) {
207         super.onNewIntent(intent);
208         if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(intent.getAction())) {
209             // This is called when managed provisioning completes successfully without reboot.
210             handleStatusUpdate(RESULT_OK, intent);
211         } else if (ACTION_TEST_RESULT.equals(intent.getAction())) {
212             // Called when subtest cannot communicate test result from the profile via setResult().
213             handleLaunchTestResult(RESULT_OK, intent.getParcelableExtra(EXTRA_RESULT));
214         }
215     }
216 
217     @Override
handleActivityResult(int requestCode, int resultCode, Intent data)218     protected void handleActivityResult(int requestCode, int resultCode, Intent data) {
219         switch (requestCode) {
220             case REQUEST_MANAGED_PROVISIONING:
221                 return;
222             case REQUEST_PROFILE_OWNER_STATUS:
223                 // Called after queryProfileOwner()
224                 handleStatusUpdate(resultCode, data);
225                 break;
226             case REQUEST_CHECK_DISK_ENCRYPTION:
227                 // Called after checkDiskEncryption()
228                 handleDiskEncryptionStatus(resultCode, data);
229                 break;
230             case REQUEST_SET_LOCK_FOR_ENCRYPTION:
231                 // Called after handleDiskEncryptionStatus() to set screen lock if necessary
232                 handleSetLockForEncryption();
233                 break;
234             case REQUEST_INTENT_FILTERS_STATUS:
235                 // Called after checkIntentFilters()
236                 handleIntentFiltersStatus(resultCode);
237                 break;
238             case REQUEST_DELETE_MANAGED_PROFILE:
239                 // Called during finish()
240                 finishAfterProfileDeleted();
241                 break;
242             default:
243                 super.handleActivityResult(requestCode, resultCode, data);
244         }
245     }
246 
handleStatusUpdate(int resultCode, Intent data)247     private void handleStatusUpdate(int resultCode, Intent data) {
248         boolean provisioned = data != null &&
249                 data.getBooleanExtra(ByodHelperActivity.EXTRA_PROVISIONED, false);
250         setProfileOwnerTestResult((provisioned && resultCode == RESULT_OK) ?
251                 TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
252     }
253 
254     @Override
finish()255     public void finish() {
256         // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
257         // clean up the provisioned profile.
258         Intent intent = new Intent(ByodHelperActivity.ACTION_REMOVE_MANAGED_PROFILE);
259         // Wait until the managed profile is deleted before returning to the previous
260         // activity, to ensure the deletion is not interrupted.
261         startActivityForResult(intent, REQUEST_DELETE_MANAGED_PROFILE);
262     }
263 
finishAfterProfileDeleted()264     private void finishAfterProfileDeleted() {
265         mByodFlowTestHelper.tearDown();
266         super.finish();
267     }
268 
269     @Override
setupTests(ArrayTestListAdapter adapter)270     protected void setupTests(ArrayTestListAdapter adapter) {
271         mProfileOwnerInstalled = new DialogTestListItem(this,
272                 R.string.provisioning_byod_profileowner,
273                 "BYOD_ProfileOwnerInstalled") {
274             @Override
275             public void performTest(DialogTestListActivity activity) {
276                 queryProfileOwner(true);
277             }
278         };
279 
280         mDiskEncryptionTest = new DialogTestListItem(this,
281                 R.string.provisioning_byod_disk_encryption,
282                 "BYOD_DiskEncryptionTest") {
283             @Override
284             public void performTest(DialogTestListActivity activity) {
285                 checkDiskEncryption();
286             }
287         };
288 
289         /*
290          * To keep the image in this test up to date, use the instructions in
291          * {@link ByodIconSamplerActivity}.
292          */
293 
294         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
295             mWorkAppVisibleTest = new DialogTestListItemWithIcon(this,
296                     R.string.provisioning_byod_workapps_visible,
297                     "BYOD_WorkAppVisibleTest",
298                     R.string.provisioning_byod_workapps_visible_instruction,
299                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
300                     R.drawable.badged_icon);
301 
302             mConfirmWorkCredentials = new DialogTestListItem(this,
303                     R.string.provisioning_byod_confirm_work_credentials,
304                     "BYOD_ConfirmWorkCredentials",
305                     R.string.provisioning_byod_confirm_work_credentials_description,
306                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
307 
308             mPatternWorkChallenge = new DialogTestListItem(this,
309                     R.string.provisioning_byod_pattern_work_challenge,
310                     "BYOD_PatternWorkChallenge",
311                     R.string.provisioning_byod_pattern_work_challenge_description,
312                     new Intent(ByodHelperActivity.ACTION_TEST_PATTERN_WORK_CHALLENGE));
313 
314             mWiFiDataUsageSettingsVisibleTest = new DialogTestListItem(this,
315                     R.string.provisioning_byod_wifi_data_usage_settings,
316                     "BYOD_WiFiDataUsageSettingsVisibleTest",
317                     R.string.provisioning_byod_wifi_data_usage_settings_instruction,
318                     new Intent(Settings.ACTION_SETTINGS));
319         }
320 
321         /* Disable due to b/111734436.
322         Intent workStatusToast = new Intent(WorkStatusTestActivity.ACTION_WORK_STATUS_TOAST);
323         workStatusToast.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
324         mWorkStatusBarToastTest = new DialogTestListItem(this,
325                 R.string.provisioning_byod_work_status_toast,
326                 "BYOD_WorkStatusBarToastTest",
327                 R.string.provisioning_byod_work_status_toast_instruction,
328                 workStatusToast);
329         */
330 
331         mNonMarketAppsTest = TestListItem.newTest(this,
332                 R.string.provisioning_byod_non_market_apps,
333                 NonMarketAppsActivity.class.getName(),
334                 new Intent(this, NonMarketAppsActivity.class), null);
335 
336         mUserSettingsVisibleTest = new DialogTestListItem(this,
337             R.string.provisioning_byod_user_settings,
338             "BYOD_UserSettingsVisibleTest",
339             R.string.provisioning_byod_user_settings_instruction,
340             new Intent(Settings.ACTION_SETTINGS));
341 
342         mAppSettingsVisibleTest = new DialogTestListItem(this,
343                 R.string.provisioning_byod_app_settings,
344                 "BYOD_AppSettingsVisibleTest",
345                 R.string.provisioning_byod_app_settings_instruction,
346                 new Intent(Settings.ACTION_APPLICATION_SETTINGS));
347 
348         mCredSettingsVisibleTest = new DialogTestListItem(this,
349                 R.string.provisioning_byod_cred_settings,
350                 "BYOD_CredSettingsVisibleTest",
351                 R.string.provisioning_byod_cred_settings_instruction,
352                 new Intent(Settings.ACTION_SECURITY_SETTINGS));
353 
354         mAllowNonDismissibleNotificationTest = new DialogTestListItem(this,
355                 R.string.provisioning_byod_allow_nondismissible_notification,
356                 "BYOD_AllowNonDismissibleNotificationTest",
357                 R.string.provisioning_byod_allow_nondismissible_notification_instructions,
358                 new Intent(this, NotificationActivity.class));
359 
360         mLocationSettingsVisibleTest = new DialogTestListItem(this,
361                 R.string.provisioning_byod_location_settings,
362                 "BYOD_LocationSettingsVisibleTest",
363                 R.string.provisioning_byod_location_settings_instruction,
364                 new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
365 
366         mCellularDataUsageSettingsVisibleTest = new DialogTestListItem(this,
367                 R.string.provisioning_byod_cellular_data_usage_settings,
368                 "BYOD_CellularDataUsageSettingsVisibleTest",
369                 R.string.provisioning_byod_cellular_data_usage_settings_instruction,
370                 new Intent(Settings.ACTION_SETTINGS));
371 
372         mPrintSettingsVisibleTest = new DialogTestListItem(this,
373                 R.string.provisioning_byod_print_settings,
374                 "BYOD_PrintSettingsVisibleTest",
375                 R.string.provisioning_byod_print_settings_instruction,
376                 new Intent(Settings.ACTION_PRINT_SETTINGS));
377 
378         Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
379         intent.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, false);
380         Intent chooser = Intent.createChooser(intent,
381                 getResources().getString(R.string.provisioning_cross_profile_chooser));
382         mCrossProfileIntentFiltersTestFromPersonal = new DialogTestListItem(this,
383                 R.string.provisioning_byod_cross_profile_from_personal,
384                 "BYOD_CrossProfileIntentFiltersTestFromPersonal",
385                 R.string.provisioning_byod_cross_profile_from_personal_instruction,
386                 chooser);
387 
388         mCrossProfileIntentFiltersTestFromWork = new DialogTestListItem(this,
389                 R.string.provisioning_byod_cross_profile_from_work,
390                 "BYOD_CrossProfileIntentFiltersTestFromWork",
391                 R.string.provisioning_byod_cross_profile_from_work_instruction,
392                 new Intent(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG));
393 
394         /* Disable due to b/33571176
395         mAppLinkingTest = new DialogTestListItem(this,
396                 R.string.provisioning_app_linking,
397                 "BYOD_AppLinking",
398                 R.string.provisioning_byod_app_linking_instruction,
399                 new Intent(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG));
400         */
401 
402         mKeyguardDisabledFeaturesTest = TestListItem.newTest(this,
403                 R.string.provisioning_byod_keyguard_disabled_features,
404                 KeyguardDisabledFeaturesActivity.class.getName(),
405                 new Intent(this, KeyguardDisabledFeaturesActivity.class), null);
406 
407         mAuthenticationBoundKeyTest = TestListItem.newTest(this,
408                 R.string.provisioning_byod_auth_bound_key,
409                 AuthenticationBoundKeyTestActivity.class.getName(),
410                 new Intent(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST),
411                 null);
412 
413         mVpnTest = TestListItem.newTest(this,
414                 R.string.provisioning_byod_vpn,
415                 VpnTestActivity.class.getName(),
416                 new Intent(VpnTestActivity.ACTION_VPN),
417                 null);
418 
419         mAlwaysOnVpnSettingsTest = TestListItem.newTest(this,
420                 R.string.provisioning_byod_always_on_vpn,
421                 AlwaysOnVpnSettingsTestActivity.class.getName(),
422                 new Intent(AlwaysOnVpnSettingsTestActivity.ACTION_ALWAYS_ON_VPN_SETTINGS_TEST),
423                 null);
424 
425         mDisallowAppsControlTest = TestListItem.newTest(this,
426                 R.string.provisioning_byod_disallow_apps_control,
427                 DisallowAppsControlActivity.class.getName(),
428                 new Intent(this, DisallowAppsControlActivity.class), null);
429 
430         // Test for checking if the required intent filters are set during managed provisioning.
431         mIntentFiltersTest = new DialogTestListItem(this,
432                 R.string.provisioning_byod_cross_profile_intent_filters,
433                 "BYOD_IntentFiltersTest") {
434             @Override
435             public void performTest(DialogTestListActivity activity) {
436                 checkIntentFilters();
437             }
438         };
439 
440         mCrossProfilePermissionControl = TestListItem.newTest(this,
441                 R.string.provisioning_byod_cross_profile_permission_control,
442                 CrossProfilePermissionControlActivity.class.getName(),
443                 new Intent(
444                         CrossProfilePermissionControlActivity.ACTION_CROSS_PROFILE_PERMISSION_CONTROL),
445                         null);
446 
447         mTurnOffWorkFeaturesTest = TestListItem.newTest(this,
448                 R.string.provisioning_byod_turn_off_work,
449                 TurnOffWorkActivity.class.getName(),
450                 new Intent(this, TurnOffWorkActivity.class), null);
451 
452         Intent permissionCheckIntent = new Intent(
453                 PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
454         mPermissionLockdownTest = new DialogTestListItem(this,
455                 R.string.device_profile_owner_permission_lockdown_test,
456                 "BYOD_PermissionLockdownTest",
457                 R.string.profile_owner_permission_lockdown_test_info,
458                 permissionCheckIntent);
459 
460         mSelectWorkChallenge = new DialogTestListItem(this,
461                 R.string.provisioning_byod_select_work_challenge,
462                 "BYOD_SelectWorkChallenge",
463                 R.string.provisioning_byod_select_work_challenge_description,
464                 new Intent(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE));
465 
466         mRecentsTest = TestListItem.newTest(this,
467                 R.string.provisioning_byod_recents,
468                 RecentsRedactionActivity.class.getName(),
469                 new Intent(RecentsRedactionActivity.ACTION_RECENTS).setFlags(
470                         FLAG_ACTIVITY_NEW_TASK),
471                 null);
472 
473         mOrganizationInfoTest = TestListItem.newTest(this,
474                 R.string.provisioning_byod_organization_info,
475                 OrganizationInfoTestActivity.class.getName(),
476                 new Intent(this, OrganizationInfoTestActivity.class),
477                 null);
478 
479         mKeyChainTest = TestListItem.newTest(this,
480                 R.string.provisioning_byod_keychain,
481                 KeyChainTestActivity.class.getName(),
482                 new Intent(KeyChainTestActivity.ACTION_KEYCHAIN),
483                 null);
484 
485         mParentProfilePassword = new DialogTestListItem(this,
486                 R.string.provisioning_byod_parent_profile_password,
487                 "BYOD_ParentProfilePasswordTest",
488                 R.string.provisioning_byod_parent_profile_password_description,
489                 new Intent(ByodHelperActivity.ACTION_TEST_PARENT_PROFILE_PASSWORD));
490 
491         mPersonalRingtonesTest = new DialogTestListItem(this,
492                 R.string.provisioning_byod_personal_ringtones,
493                 "BYOD_PersonalRingtones",
494                 R.string.provisioning_byod_personal_ringtones_instruction,
495                 new Intent(Settings.ACTION_SOUND_SETTINGS));
496 
497         mScreenshotTest = TestListItem.newTest(/* context= */ this,
498                 R.string.provisioning_byod_screenshot,
499                 ScreenshotTestActivity.class.getName(),
500                 new Intent(ScreenshotTestActivity.ACTION_SCREENSHOT_TEST),
501                 /* requiredFeatures= */ null);
502 
503         final Intent policyTransparencyTestIntent = new Intent(this,
504                 PolicyTransparencyTestListActivity.class);
505         policyTransparencyTestIntent.putExtra(
506                 PolicyTransparencyTestListActivity.EXTRA_MODE,
507                 PolicyTransparencyTestListActivity.MODE_MANAGED_PROFILE);
508         policyTransparencyTestIntent.putExtra(
509                 PolicyTransparencyTestActivity.EXTRA_TEST_ID, "BYOD_PolicyTransparency");
510         mPolicyTransparencyTest = TestListItem.newTest(this,
511                 R.string.device_profile_owner_policy_transparency_test,
512                 "BYOD_PolicyTransparency",
513                 policyTransparencyTestIntent, null);
514 
515         adapter.add(mProfileOwnerInstalled);
516         adapter.add(mDiskEncryptionTest);
517 
518         // Badge related tests
519         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
520             adapter.add(mWorkAppVisibleTest);
521         }
522 
523         /* Disable due to b/111734436.
524         adapter.add(mWorkStatusBarToastTest);
525         */
526 
527         // Settings related tests.
528         adapter.add(mCredSettingsVisibleTest);
529         adapter.add(mUserSettingsVisibleTest);
530         adapter.add(mAppSettingsVisibleTest);
531         adapter.add(mLocationSettingsVisibleTest);
532         adapter.add(mPrintSettingsVisibleTest);
533         adapter.add(mPersonalRingtonesTest);
534 
535         adapter.add(mCrossProfileIntentFiltersTestFromPersonal);
536         adapter.add(mCrossProfileIntentFiltersTestFromWork);
537         /* Disable due to b/33571176
538         adapter.add(mAppLinkingTest);
539         */
540         adapter.add(mIntentFiltersTest);
541         adapter.add(mCrossProfilePermissionControl);
542         adapter.add(mNonMarketAppsTest);
543         adapter.add(mPermissionLockdownTest);
544         adapter.add(mKeyguardDisabledFeaturesTest);
545         adapter.add(mAuthenticationBoundKeyTest);
546         adapter.add(mVpnTest);
547         adapter.add(mAlwaysOnVpnSettingsTest);
548         adapter.add(mTurnOffWorkFeaturesTest);
549         adapter.add(mSelectWorkChallenge);
550         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
551             adapter.add(mConfirmWorkCredentials);
552             adapter.add(mPatternWorkChallenge);
553         }
554         adapter.add(mRecentsTest);
555         adapter.add(mOrganizationInfoTest);
556         adapter.add(mParentProfilePassword);
557         adapter.add(mPolicyTransparencyTest);
558 
559         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
560             if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
561                 adapter.add(mWiFiDataUsageSettingsVisibleTest);
562             }
563         }
564 
565         mCm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
566         if(mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) != null) {
567             adapter.add(mCellularDataUsageSettingsVisibleTest);
568         }
569 
570         if (canResolveIntent(new Intent(Settings.ACTION_APPLICATION_SETTINGS))) {
571             adapter.add(mDisallowAppsControlTest);
572         }
573 
574         /* If there is an application that handles ACTION_IMAGE_CAPTURE, test that it handles it
575          * well.
576          */
577         if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
578             // Capture image intent can be resolved in primary profile, so test.
579             mCrossProfileImageCaptureSupportTest = new DialogTestListItem(this,
580                     R.string.provisioning_byod_capture_image_support,
581                     "BYOD_CrossProfileImageCaptureSupportTest",
582                     R.string.provisioning_byod_capture_image_support_info,
583                     new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_IMAGE));
584             adapter.add(mCrossProfileImageCaptureSupportTest);
585         } else {
586             // Capture image intent cannot be resolved in primary profile, so skip test.
587             Toast.makeText(ByodFlowTestActivity.this,
588                             R.string.provisioning_byod_no_image_capture_resolver, Toast.LENGTH_SHORT)
589                     .show();
590         }
591 
592         /* If there is an application that handles ACTION_VIDEO_CAPTURE, test that it handles it
593          * well.
594          */
595         if (canResolveIntent(ByodHelperActivity.getCaptureVideoIntent())) {
596             // Capture video intent can be resolved in primary profile, so test.
597             mCrossProfileVideoCaptureWithExtraOutputSupportTest = new DialogTestListItem(this,
598                     R.string.provisioning_byod_capture_video_support_with_extra_output,
599                     "BYOD_CrossProfileVideoCaptureWithExtraOutputSupportTest",
600                     R.string.provisioning_byod_capture_video_support_info,
601                     new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT));
602             adapter.add(mCrossProfileVideoCaptureWithExtraOutputSupportTest);
603             mCrossProfileVideoCaptureWithoutExtraOutputSupportTest = new DialogTestListItem(this,
604                     R.string.provisioning_byod_capture_video_support_without_extra_output,
605                     "BYOD_CrossProfileVideoCaptureWithoutExtraOutputSupportTest",
606                     R.string.provisioning_byod_capture_video_support_info,
607                     new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_VIDEO_WITHOUT_EXTRA_OUTPUT));
608             adapter.add(mCrossProfileVideoCaptureWithoutExtraOutputSupportTest);
609         } else {
610             // Capture video intent cannot be resolved in primary profile, so skip test.
611             Toast.makeText(ByodFlowTestActivity.this,
612                     R.string.provisioning_byod_no_video_capture_resolver, Toast.LENGTH_SHORT)
613                     .show();
614         }
615 
616         adapter.add(mKeyChainTest);
617 
618         /* If there is an application that handles RECORD_SOUND_ACTION, test that it handles it
619          * well.
620          */
621         if (canResolveIntent(ByodHelperActivity.getCaptureAudioIntent())) {
622             // Capture audio intent can be resolved in primary profile, so test.
623             mCrossProfileAudioCaptureSupportTest = new DialogTestListItem(this,
624                     R.string.provisioning_byod_capture_audio_support,
625                     "BYOD_CrossProfileAudioCaptureSupportTest",
626                     R.string.provisioning_byod_capture_audio_support_info,
627                     new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_AUDIO));
628             adapter.add(mCrossProfileAudioCaptureSupportTest);
629         } else {
630             // Capture audio intent cannot be resolved in primary profile, so skip test.
631             Toast.makeText(ByodFlowTestActivity.this,
632                     R.string.provisioning_byod_no_audio_capture_resolver, Toast.LENGTH_SHORT)
633                     .show();
634         }
635 
636         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
637             mEnableLocationModeTest = TestListItem.newTest(this,
638                     R.string.provisioning_byod_location_mode_enable,
639                     LocationTestActivity.TEST_ID_LOCATION_ENABLED,
640                     new Intent(LocationTestActivity.ACTION_TEST_LOCATION_ENABLED),
641                     null);
642             mDisableLocationModeThroughMainSwitchTest = TestListItem.newTest(this,
643                     R.string.provisioning_byod_location_mode_disable,
644                     LocationTestActivity.TEST_ID_LOCATION_DISABLED,
645                     new Intent(LocationTestActivity.ACTION_TEST_LOCATION_DISABLED),
646                     null);
647             mDisableLocationModeThroughWorkSwitchTest = TestListItem.newTest(this,
648                     R.string.provisioning_byod_work_location_mode_disable,
649                     LocationTestActivity.TEST_ID_WORK_LOCATION_DISABLED,
650                     new Intent(LocationTestActivity.ACTION_TEST_WORK_LOCATION_DISABLED),
651                     null);
652             mPrimaryLocationWhenWorkDisabledTest = TestListItem.newTest(this,
653                     R.string.provisioning_byod_primary_location_when_work_disabled,
654                     LocationTestActivity.TEST_ID_WORK_LOCATION_DISABLED_PRIMARY,
655                     new Intent(LocationTestActivity.ACTION_TEST_WORK_LOCATION_DISABLED_PRIMARY),
656                     null);
657             adapter.add(mEnableLocationModeTest);
658             adapter.add(mDisableLocationModeThroughMainSwitchTest);
659             adapter.add(mDisableLocationModeThroughWorkSwitchTest);
660             adapter.add(mPrimaryLocationWhenWorkDisabledTest);
661         } else {
662             // The system does not support GPS feature, so skip test.
663             Toast.makeText(ByodFlowTestActivity.this,
664                     R.string.provisioning_byod_no_gps_location_feature, Toast.LENGTH_SHORT)
665                     .show();
666         }
667 
668         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
669             mWidgetTest = TestListItem.newTest(this,
670                     R.string.provisioning_byod_work_profile_widget,
671                     WorkProfileWidgetActivity.class.getName(),
672                     new Intent(WorkProfileWidgetActivity.ACTION_TEST_WORK_PROFILE_WIDGET),
673                     new String[]{PackageManager.FEATURE_APP_WIDGETS});
674             adapter.add(mWidgetTest);
675         }
676 
677         adapter.add(new DialogTestListItem(this,
678                 R.string.provisioning_byod_uninstall_work_app,
679                 "BYOD_UninstallWorkApp",
680                 R.string.provisioning_byod_uninstall_work_app_instruction,
681                 createInstallWorkProfileAppIntent()));
682 
683         adapter.add(new DialogTestListItem(this,
684                 R.string.provisioning_byod_launch_work_tab,
685                 "BYOD_LaunchWorkTab",
686                 R.string.provisioning_byod_launch_work_tab_instruction,
687                 createLaunchWorkTabIntent()));
688 
689         adapter.add(mScreenshotTest);
690         adapter.add(mAllowNonDismissibleNotificationTest);
691     }
692 
createInstallWorkProfileAppIntent()693     private Intent createInstallWorkProfileAppIntent() {
694         // We place the APK file in /data/local/tmp to make it visible from the work profile.
695         return new Intent(ByodHelperActivity.ACTION_INSTALL_APK)
696                 .putExtra(ByodHelperActivity.EXTRA_ALLOW_NON_MARKET_APPS, true)
697                 .putExtra(ByodHelperActivity.EXTRA_PARAMETER_1, HELPER_APP_PATH);
698     }
699 
createLaunchWorkTabIntent()700     private Intent createLaunchWorkTabIntent() {
701         return new Intent(Intent.ACTION_SHOW_WORK_APPS)
702                 .addCategory(Intent.CATEGORY_HOME)
703                 .addCategory(Intent.CATEGORY_LAUNCHER_APP)
704                 .addFlags(FLAG_ACTIVITY_NEW_TASK);
705     }
706 
707     // Return whether the intent can be resolved in the current profile
canResolveIntent(Intent intent)708     private boolean canResolveIntent(Intent intent) {
709         return intent.resolveActivity(getPackageManager()) != null;
710     }
711 
712     @Override
clearRemainingState(final DialogTestListItem test)713     protected void clearRemainingState(final DialogTestListItem test) {
714         super.clearRemainingState(test);
715         if (ByodHelperActivity.ACTION_NOTIFICATION.equals(
716                 test.getManualTestIntent().getAction())) {
717             try {
718                 startActivity(new Intent(
719                         ByodHelperActivity.ACTION_CLEAR_NOTIFICATION));
720             } catch (ActivityNotFoundException e) {
721                 // User shouldn't run this test before work profile is set up.
722             }
723         }
724     }
725 
queryProfileOwner(boolean showToast)726     private void queryProfileOwner(boolean showToast) {
727         try {
728             // Set execution start time for counting test execution time.
729             mStartTime = System.currentTimeMillis();
730             Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
731             startActivityForResult(intent, REQUEST_PROFILE_OWNER_STATUS);
732         }
733         catch (ActivityNotFoundException e) {
734             Log.d(TAG, "queryProfileOwner: ActivityNotFoundException", e);
735             setProfileOwnerTestResult(TestResult.TEST_RESULT_FAILED);
736             if (showToast) {
737                 Utils.showToast(this, R.string.provisioning_byod_no_activity);
738             }
739         }
740     }
741 
setProfileOwnerTestResult(int result)742     private void setProfileOwnerTestResult(int result) {
743         setTestResult(mProfileOwnerInstalled, result);
744         if (result == TestResult.TEST_RESULT_FAILED) {
745             clearProvisioningCompleteBroadcastStatus(this);
746             startPeriodicProvisioningCheckIfNecessary();
747         }
748     }
749 
checkDiskEncryption()750     private void checkDiskEncryption() {
751         try {
752             Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_DISK_ENCRYPTION);
753             startActivityForResult(intent, REQUEST_CHECK_DISK_ENCRYPTION);
754         } catch (ActivityNotFoundException e) {
755             Log.d(TAG, "checkDiskEncryption: ActivityNotFoundException", e);
756             setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
757             Utils.showToast(this, R.string.provisioning_byod_no_activity);
758         }
759     }
760 
handleDiskEncryptionStatus(int resultCode, Intent data)761     private void handleDiskEncryptionStatus(int resultCode, Intent data) {
762         if (resultCode != RESULT_OK || data == null) {
763             Log.e(TAG, "Failed to get result for disk encryption, result code: " + resultCode);
764             setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
765             return;
766         }
767 
768         final int status = data.getIntExtra(ByodHelperActivity.EXTRA_ENCRYPTION_STATUS,
769                 DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED);
770         switch (status) {
771             case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
772             case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
773                 setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_PASSED);
774                 break;
775             case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY:
776                 if (!mKeyguardManager.isDeviceSecure()) {
777                     Utils.setScreenLock(this, REQUEST_SET_LOCK_FOR_ENCRYPTION);
778                     return;
779                 }
780                 Log.e(TAG, "Disk encryption key is not entangled with lock screen credentials");
781                 Toast.makeText(this, R.string.provisioning_byod_disk_encryption_default_key_toast,
782                         Toast.LENGTH_LONG).show();
783                 // fall through
784             default:
785                 setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
786         }
787 
788         if (mKeyguardManager.isDeviceSecure()) {
789             Utils.removeScreenLock(this);
790         }
791     }
792 
handleSetLockForEncryption()793     private void handleSetLockForEncryption() {
794         if (mKeyguardManager.isDeviceSecure()) {
795             checkDiskEncryption();
796         } else {
797             setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
798             Toast.makeText(this, R.string.provisioning_byod_disk_encryption_no_pin_toast,
799                     Toast.LENGTH_LONG).show();
800         }
801     }
802 
checkIntentFilters()803     private void checkIntentFilters() {
804         try {
805             // Enable component HandleIntentActivity before intent filters are checked.
806             setHandleIntentActivityEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
807             // We disable the ByodHelperActivity in the primary profile. So, this intent
808             // will be handled by the ByodHelperActivity in the managed profile.
809             Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_INTENT_FILTERS);
810             startActivityForResult(intent, REQUEST_INTENT_FILTERS_STATUS);
811         } catch (ActivityNotFoundException e) {
812             // Disable component HandleIntentActivity if intent filters check fails.
813             setHandleIntentActivityEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
814             Log.d(TAG, "checkIntentFilters: ActivityNotFoundException", e);
815             setTestResult(mIntentFiltersTest, TestResult.TEST_RESULT_FAILED);
816             Utils.showToast(this, R.string.provisioning_byod_no_activity);
817         }
818     }
819 
handleIntentFiltersStatus(int resultCode)820     private void handleIntentFiltersStatus(int resultCode) {
821         // Disable component HandleIntentActivity after intent filters are checked.
822         setHandleIntentActivityEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
823         // we use the resultCode from ByodHelperActivity in the managed profile to know if certain
824         // intents fired from the managed profile are forwarded.
825         final boolean intentFiltersSetForManagedIntents = (resultCode == RESULT_OK);
826         // Since the ByodFlowTestActivity is running in the primary profile, we directly use
827         // the IntentFiltersTestHelper to know if certain intents fired from the primary profile
828         // are forwarded.
829         final boolean intentFiltersSetForPrimaryIntents =
830                 new IntentFiltersTestHelper(this).checkCrossProfileIntentFilters(
831                         IntentFiltersTestHelper.FLAG_INTENTS_FROM_PRIMARY);
832         final boolean intentFiltersSet =
833                 intentFiltersSetForPrimaryIntents & intentFiltersSetForManagedIntents;
834         setTestResult(mIntentFiltersTest,
835                 intentFiltersSet ? TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
836     }
837 
setHandleIntentActivityEnabledSetting(final int enableState)838     private void setHandleIntentActivityEnabledSetting(final int enableState) {
839         getPackageManager().setComponentEnabledSetting(
840             new ComponentName(ByodFlowTestActivity.this, HandleIntentActivity.class.getName()),
841             enableState, PackageManager.DONT_KILL_APP);
842     }
843 
markProvisioningCompleteBroadcastReceived(Context context)844     private static void markProvisioningCompleteBroadcastReceived(Context context) {
845         markProvisioningCompleteBroadcastWithStatus(context,
846                 PREFERENCE_PROVISIONING_COMPLETE_STATUS_RECEIVED);
847     }
848 
markProvisioningCompleteBroadcastProcessed(Context context)849     private static void markProvisioningCompleteBroadcastProcessed(Context context) {
850         markProvisioningCompleteBroadcastWithStatus(context,
851                 PREFERENCE_PROVISIONING_COMPLETE_STATUS_PROCESSED);
852     }
853 
clearProvisioningCompleteBroadcastStatus(Context context)854     private static void clearProvisioningCompleteBroadcastStatus(Context context) {
855         markProvisioningCompleteBroadcastWithStatus(context,
856                 PREFERENCE_PROVISIONING_COMPLETE_STATUS_NOT_RECEIVED);
857     }
858 
markProvisioningCompleteBroadcastWithStatus(Context context, int status)859     private static void markProvisioningCompleteBroadcastWithStatus(Context context, int status) {
860         final SharedPreferences prefs = getProvisioningPreferences(context);
861         final SharedPreferences.Editor editor = prefs.edit();
862         editor.putInt(PREFERENCE_PROVISIONING_COMPLETE_STATUS, status);
863         editor.commit();
864     }
865 
isProvisioningCompleteBroadcastReceived(Context context)866     private static boolean isProvisioningCompleteBroadcastReceived(Context context) {
867         return getProvisioningPreferences(context)
868                 .getInt(PREFERENCE_PROVISIONING_COMPLETE_STATUS, 0) ==
869                 PREFERENCE_PROVISIONING_COMPLETE_STATUS_RECEIVED;
870     }
871 
isProvisioningCompleteBroadcastProcessed(Context context)872     private static boolean isProvisioningCompleteBroadcastProcessed(Context context) {
873         return getProvisioningPreferences(context)
874                 .getInt(PREFERENCE_PROVISIONING_COMPLETE_STATUS, 0) ==
875                 PREFERENCE_PROVISIONING_COMPLETE_STATUS_PROCESSED;
876     }
877 
getProvisioningPreferences(Context context)878     private static SharedPreferences getProvisioningPreferences(Context context) {
879         return context.getSharedPreferences(PROVISIONING_PREFERENCES, MODE_PRIVATE);
880     }
881 }
882