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