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