blob: fdf0089156ce2a8f53838276aebbe0c23106b621 [file] [log] [blame]
Rubin Xu55d22d42014-09-24 19:56:58 +01001/*
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
17package com.android.cts.verifier.managedprovisioning;
18
19import android.app.AlertDialog;
Rubin Xu55d22d42014-09-24 19:56:58 +010020import android.app.admin.DevicePolicyManager;
21import android.content.ActivityNotFoundException;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
Rubin Xu55d22d42014-09-24 19:56:58 +010026import android.content.pm.PackageManager;
27import android.os.Bundle;
28import android.provider.Settings;
29import android.util.Log;
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +000030import android.view.LayoutInflater;
Rubin Xu55d22d42014-09-24 19:56:58 +010031import android.view.View;
32import android.view.ViewGroup;
33import android.view.View.OnClickListener;
34import android.widget.ArrayAdapter;
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +000035import android.widget.ImageView;
Rubin Xu55d22d42014-09-24 19:56:58 +010036import android.widget.ListView;
37import android.widget.TextView;
38import android.widget.Toast;
39
40import com.android.cts.verifier.PassFailButtons;
41import com.android.cts.verifier.R;
42import com.android.cts.verifier.TestListActivity;
43
44import java.util.ArrayList;
45import java.util.List;
46
47/**
48 * CTS verifier test for BYOD managed provisioning flow.
49 * This activity is responsible for starting the managed provisioning flow and verify the outcome of provisioning.
50 * It performs the following verifications:
51 * Full disk encryption is enabled.
52 * Profile owner is correctly installed.
53 * Profile owner shows up in the Settings app.
54 * Badged work apps show up in launcher.
55 * The first two verifications are performed automatically, by interacting with profile owner using
56 * cross-profile intents, while the last two are carried out manually by the user.
57 */
58public class ByodFlowTestActivity extends PassFailButtons.ListActivity {
59
60 private final String TAG = "ByodFlowTestActivity";
61 private static final int REQUEST_STATUS = 1;
62
63 private ComponentName mAdminReceiverComponent;
64
Rubin Xuc2b00d82015-02-02 11:30:26 +000065 private TestAdapter mTestListAdapter;
Rubin Xu55d22d42014-09-24 19:56:58 +010066 private View mStartProvisioningButton;
67 private List<TestItem> mTests = new ArrayList<TestItem>();
68
69 protected DevicePolicyManager mDevicePolicyManager;
70
71 private TestItem mProfileOwnerInstalled;
Rubin Xuc2b00d82015-02-02 11:30:26 +000072 private TestItem mProfileAccountVisibleTest;
Rubin Xu55d22d42014-09-24 19:56:58 +010073 private TestItem mDeviceAdminVisibleTest;
74 private TestItem mWorkAppVisibleTest;
Alexandra Gherghinaaa24ed72014-10-08 01:11:32 +010075 private TestItem mCrossProfileIntentFiltersTest;
Robin Lee020f1852015-01-15 11:56:05 +000076 private TestItem mDisableNonMarketTest;
77 private TestItem mEnableNonMarketTest;
Alexandra Gherghina2c672b72015-01-22 11:20:23 +000078 private TestItem mWorkNotificationBadgedTest;
Rubin Xuc2b00d82015-02-02 11:30:26 +000079 private TestItem mAppSettingsVisibleTest;
80 private TestItem mLocationSettingsVisibleTest;
81 private TestItem mCredSettingsVisibleTest;
82 private TestItem mPrintSettingsVisibleTest;
Sander Alewijnse7e24fda2015-03-26 17:41:57 +000083 private TestItem mCrossProfileImageCaptureSupportTest;
84 private TestItem mCrossProfileVideoCaptureSupportTest;
85 private TestItem mCrossProfileAudioCaptureSupportTest;
Rubin Xuc2b00d82015-02-02 11:30:26 +000086
87 private int mCurrentTestPosition;
Rubin Xu55d22d42014-09-24 19:56:58 +010088
89 @Override
90 protected void onCreate(Bundle savedInstanceState) {
91 super.onCreate(savedInstanceState);
92 mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
93 mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
94 disableComponent();
95
96 setContentView(R.layout.provisioning_byod);
97 setInfoResources(R.string.provisioning_byod, R.string.provisioning_byod_info, -1);
98 setPassFailButtonClickListeners();
99 getPassButton().setEnabled(false);
100 setResult(RESULT_CANCELED);
101
102 setupTests();
103
Rubin Xuc2b00d82015-02-02 11:30:26 +0000104 mTestListAdapter = new TestAdapter(this);
105 setListAdapter(mTestListAdapter);
106 mTestListAdapter.addAll(mTests);
107
108 mCurrentTestPosition = 0;
Rubin Xu55d22d42014-09-24 19:56:58 +0100109
110 mStartProvisioningButton = findViewById(R.id.byod_start);
111 mStartProvisioningButton.setOnClickListener(new OnClickListener() {
112 @Override
113 public void onClick(View v) {
114 startByodProvisioning();
115 }
116 });
117
118 // If we are started by managed provisioning (fresh managed provisioning after encryption
119 // reboot), redirect the user back to the main test list. This is because the test result
120 // is only saved by the parent TestListActivity, and if we did allow the user to proceed
121 // here, the test result would be lost when this activity finishes.
122 if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(getIntent().getAction())) {
123 startActivity(new Intent(this, TestListActivity.class));
124 // Calling super.finish() because we delete managed profile in our overridden of finish(),
125 // which is not what we want to do here.
126 super.finish();
127 } else {
128 queryProfileOwner(false);
129 }
130 }
131
132 @Override
133 protected void onNewIntent(Intent intent) {
134 // This is called when managed provisioning completes successfully without reboot.
135 super.onNewIntent(intent);
136 if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(intent.getAction())) {
137 handleStatusUpdate(intent);
138 }
139 }
140
141 @Override
142 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
143 // Called after queryProfileOwner()
144 super.onActivityResult(requestCode, resultCode, data);
145 if (requestCode == REQUEST_STATUS && resultCode == RESULT_OK) {
146 handleStatusUpdate(data);
147 }
148 }
149
150 private void handleStatusUpdate(Intent data) {
151 boolean provisioned = data.getBooleanExtra(ByodHelperActivity.EXTRA_PROVISIONED, false);
152 setTestResult(mProfileOwnerInstalled, provisioned ? TestResult.Passed : TestResult.Failed);
153 }
154
155 @Override
156 public void finish() {
157 // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
158 // clean up the provisioned profile.
159 requestDeleteProfileOwner();
160 super.finish();
161 }
162
163 private void setupTests() {
164 mProfileOwnerInstalled = new TestItem(this, R.string.provisioning_byod_profileowner) {
165 @Override
166 public void performTest(ByodFlowTestActivity activity) {
167 queryProfileOwner(true);
168 }
169 };
170
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000171 /*
172 * To keep the image in this test up to date, use the instructions in
173 * {@link ByodIconSamplerActivity}.
174 */
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000175 mWorkAppVisibleTest = new TestItemWithIcon(this,
176 R.string.provisioning_byod_workapps_visible,
Rubin Xuc2b00d82015-02-02 11:30:26 +0000177 R.string.provisioning_byod_workapps_visible_instruction,
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000178 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
179 R.drawable.badged_icon);
180
181 mWorkNotificationBadgedTest = new TestItemWithIcon(this,
182 R.string.provisioning_byod_work_notification,
183 R.string.provisioning_byod_work_notification_instruction,
184 new Intent(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION),
185 R.drawable.ic_corp_icon);
Rubin Xu55d22d42014-09-24 19:56:58 +0100186
Robin Lee020f1852015-01-15 11:56:05 +0000187 mDisableNonMarketTest = new TestItem(this, R.string.provisioning_byod_nonmarket_deny,
188 R.string.provisioning_byod_nonmarket_deny_info,
189 new Intent(ByodHelperActivity.ACTION_INSTALL_APK)
190 .putExtra(ByodHelperActivity.EXTRA_ALLOW_NON_MARKET_APPS, false));
191
192 mEnableNonMarketTest = new TestItem(this, R.string.provisioning_byod_nonmarket_allow,
193 R.string.provisioning_byod_nonmarket_allow_info,
194 new Intent(ByodHelperActivity.ACTION_INSTALL_APK)
195 .putExtra(ByodHelperActivity.EXTRA_ALLOW_NON_MARKET_APPS, true));
196
Rubin Xuc2b00d82015-02-02 11:30:26 +0000197 mProfileAccountVisibleTest = new TestItem(this, R.string.provisioning_byod_profile_visible,
198 R.string.provisioning_byod_profile_visible_instruction,
199 new Intent(Settings.ACTION_SETTINGS));
200
201 mAppSettingsVisibleTest = new TestItem(this, R.string.provisioning_byod_app_settings,
202 R.string.provisioning_byod_app_settings_instruction,
203 new Intent(Settings.ACTION_APPLICATION_SETTINGS));
204
205 mDeviceAdminVisibleTest = new TestItem(this, R.string.provisioning_byod_admin_visible,
206 R.string.provisioning_byod_admin_visible_instruction,
207 new Intent(Settings.ACTION_SECURITY_SETTINGS));
208
209 mCredSettingsVisibleTest = new TestItem(this, R.string.provisioning_byod_cred_settings,
210 R.string.provisioning_byod_cred_settings_instruction,
211 new Intent(Settings.ACTION_SECURITY_SETTINGS));
212
213 mLocationSettingsVisibleTest = new TestItem(this,
214 R.string.provisioning_byod_location_settings,
215 R.string.provisioning_byod_location_settings_instruction,
216 new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
217
218 mPrintSettingsVisibleTest = new TestItem(this, R.string.provisioning_byod_print_settings,
219 R.string.provisioning_byod_print_settings_instruction,
220 new Intent(Settings.ACTION_PRINT_SETTINGS));
221
Alexandra Gherghinaaa24ed72014-10-08 01:11:32 +0100222 Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
Rubin Xuc2b00d82015-02-02 11:30:26 +0000223 Intent chooser = Intent.createChooser(intent,
224 getResources().getString(R.string.provisioning_cross_profile_chooser));
Alexandra Gherghinaaa24ed72014-10-08 01:11:32 +0100225 mCrossProfileIntentFiltersTest = new TestItem(this,
226 R.string.provisioning_byod_cross_profile,
227 R.string.provisioning_byod_cross_profile_instruction,
228 chooser);
229
Rubin Xu55d22d42014-09-24 19:56:58 +0100230 mTests.add(mProfileOwnerInstalled);
Rubin Xuc2b00d82015-02-02 11:30:26 +0000231
232 // Badge related tests
Rubin Xu55d22d42014-09-24 19:56:58 +0100233 mTests.add(mWorkAppVisibleTest);
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000234 mTests.add(mWorkNotificationBadgedTest);
Rubin Xuc2b00d82015-02-02 11:30:26 +0000235
236 // Settings related tests.
237 mTests.add(mProfileAccountVisibleTest);
238 mTests.add(mDeviceAdminVisibleTest);
239 mTests.add(mCredSettingsVisibleTest);
240 mTests.add(mAppSettingsVisibleTest);
241 mTests.add(mLocationSettingsVisibleTest);
242 mTests.add(mPrintSettingsVisibleTest);
243
Alexandra Gherghinaaa24ed72014-10-08 01:11:32 +0100244 mTests.add(mCrossProfileIntentFiltersTest);
Robin Lee020f1852015-01-15 11:56:05 +0000245 mTests.add(mDisableNonMarketTest);
246 mTests.add(mEnableNonMarketTest);
Sander Alewijnse7e24fda2015-03-26 17:41:57 +0000247
248 if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
249 // Capture image intent can be resolved in primary profile, so test.
250 mCrossProfileImageCaptureSupportTest = new TestItem(this,
251 R.string.provisioning_byod_capture_image_support,
252 R.string.provisioning_byod_capture_image_support_info,
253 new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_IMAGE));
254 mTests.add(mCrossProfileImageCaptureSupportTest);
255 } else {
256 // Capture image intent cannot be resolved in primary profile, so skip test.
257 Toast.makeText(ByodFlowTestActivity.this,
258 R.string.provisioning_byod_no_image_capture_resolver, Toast.LENGTH_SHORT)
259 .show();
260 }
261
262 if (canResolveIntent(ByodHelperActivity.getCaptureVideoIntent())) {
263 // Capture video intent can be resolved in primary profile, so test.
264 mCrossProfileVideoCaptureSupportTest = new TestItem(this,
265 R.string.provisioning_byod_capture_video_support,
266 R.string.provisioning_byod_capture_video_support_info,
267 new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_VIDEO));
268 mTests.add(mCrossProfileVideoCaptureSupportTest);
269 } else {
270 // Capture video intent cannot be resolved in primary profile, so skip test.
271 Toast.makeText(ByodFlowTestActivity.this,
272 R.string.provisioning_byod_no_video_capture_resolver, Toast.LENGTH_SHORT)
273 .show();
274 }
275
276 /* TODO: reinstate when bug b/20131958 is fixed
277 if (canResolveIntent(ByodHelperActivity.getCaptureAudioIntent())) {
278 // Capture audio intent can be resolved in primary profile, so test.
279 mCrossProfileAudioCaptureSupportTest = new TestItem(this,
280 R.string.provisioning_byod_capture_audio_support,
281 R.string.provisioning_byod_capture_audio_support_info,
282 new Intent(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_AUDIO));
283 mTests.add(mCrossProfileAudioCaptureSupportTest);
284 } else {
285 // Capture audio intent cannot be resolved in primary profile, so skip test.
286 Toast.makeText(ByodFlowTestActivity.this,
287 R.string.provisioning_byod_no_audio_capture_resolver, Toast.LENGTH_SHORT)
288 .show();
289 }
290 */
Rubin Xu55d22d42014-09-24 19:56:58 +0100291 }
292
293 @Override
294 protected void onListItemClick(ListView l, View v, int position, long id) {
295 super.onListItemClick(l, v, position, id);
Rubin Xuc2b00d82015-02-02 11:30:26 +0000296 mCurrentTestPosition = position;
Rubin Xu55d22d42014-09-24 19:56:58 +0100297 TestItem test = (TestItem) getListAdapter().getItem(position);
298 test.performTest(this);
299 }
300
Sander Alewijnse7e24fda2015-03-26 17:41:57 +0000301 // Return whether the intent can be resolved in the current profile
302 private boolean canResolveIntent(Intent intent) {
303 return intent.resolveActivity(getPackageManager()) != null;
304 }
305
Rubin Xu55d22d42014-09-24 19:56:58 +0100306 private void showManualTestDialog(final TestItem test) {
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000307 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this)
Rubin Xu55d22d42014-09-24 19:56:58 +0100308 .setIcon(android.R.drawable.ic_dialog_info)
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000309 .setTitle(R.string.provisioning_byod)
Rubin Xu55d22d42014-09-24 19:56:58 +0100310 .setNeutralButton(R.string.provisioning_byod_go, null)
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000311 .setPositiveButton(R.string.pass_button_text, new AlertDialog.OnClickListener() {
Rubin Xu55d22d42014-09-24 19:56:58 +0100312 @Override
313 public void onClick(DialogInterface dialog, int which) {
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000314 clearRemainingState(test);
Rubin Xu55d22d42014-09-24 19:56:58 +0100315 setTestResult(test, TestResult.Passed);
316 }
317 })
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000318 .setNegativeButton(R.string.fail_button_text, new AlertDialog.OnClickListener() {
Rubin Xu55d22d42014-09-24 19:56:58 +0100319 @Override
320 public void onClick(DialogInterface dialog, int which) {
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000321 clearRemainingState(test);
Rubin Xu55d22d42014-09-24 19:56:58 +0100322 setTestResult(test, TestResult.Failed);
323 }
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000324 });
325 View customView = test.getCustomView();
326 if (customView != null) {
327 dialogBuilder.setView(customView);
328 } else {
329 dialogBuilder.setMessage(test.getManualTestInstruction());
330 }
Rubin Xuc2b00d82015-02-02 11:30:26 +0000331 final AlertDialog dialog = dialogBuilder.show();
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000332 // Note: Setting the OnClickListener on the Dialog rather than the Builder, prevents the
333 // dialog being dismissed on onClick.
Rubin Xu55d22d42014-09-24 19:56:58 +0100334 dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() {
335 @Override
336 public void onClick(View v) {
Rubin Xuc2b00d82015-02-02 11:30:26 +0000337 try {
338 ByodFlowTestActivity.this.startActivity(test.getManualTestIntent());
339 } catch (ActivityNotFoundException e) {
340 Toast.makeText(ByodFlowTestActivity.this,
341 "Cannot start " + test.getManualTestIntent(), Toast.LENGTH_LONG).show();
342 setTestResult(test, TestResult.Failed);
343 dialog.dismiss();
344 }
Rubin Xu55d22d42014-09-24 19:56:58 +0100345 }
346 });
347 }
348
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000349 private void clearRemainingState(final TestItem test) {
350 if (WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION.equals(
351 test.getManualTestIntent().getAction())) {
Rubin Xuc2b00d82015-02-02 11:30:26 +0000352 try {
353 ByodFlowTestActivity.this.startActivity(new Intent(
354 WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION));
355 } catch (ActivityNotFoundException e) {
356 // User shouldn't run this test before work profile is set up.
357 }
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000358 }
359 }
360
Rubin Xu55d22d42014-09-24 19:56:58 +0100361 private void setTestResult(TestItem test, TestResult result) {
362 test.setPassFailState(result);
363
364 boolean testSucceeds = true;
365 for(TestItem aTest : mTests) {
366 testSucceeds &= (aTest.getPassFailState() == TestResult.Passed);
367 }
368 getPassButton().setEnabled(testSucceeds);
Rubin Xuc2b00d82015-02-02 11:30:26 +0000369 mTestListAdapter.notifyDataSetChanged();
370
371 this.getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
Rubin Xu55d22d42014-09-24 19:56:58 +0100372 }
373
374 private void startByodProvisioning() {
375 Intent sending = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
376 sending.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
377 mAdminReceiverComponent.getPackageName());
378 sending.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminReceiverComponent);
379
380 if (sending.resolveActivity(getPackageManager()) != null) {
381 // ManagedProvisioning must be started with startActivityForResult, but we don't
382 // care about the result, so passing 0 as a requestCode
383 startActivityForResult(sending, 0);
384 } else {
385 showToast(R.string.provisioning_byod_disabled);
386 }
387 }
388
389 private void queryProfileOwner(boolean showToast) {
390 try {
391 Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
392 startActivityForResult(intent, REQUEST_STATUS);
393 }
394 catch (ActivityNotFoundException e) {
395 Log.d(TAG, "queryProfileOwner: ActivityNotFoundException", e);
396 setTestResult(mProfileOwnerInstalled, TestResult.Failed);
397 if (showToast) {
398 showToast(R.string.provisioning_byod_no_activity);
399 }
400 }
401 }
402
403 private void requestDeleteProfileOwner() {
404 try {
405 Intent intent = new Intent(ByodHelperActivity.ACTION_REMOVE_PROFILE_OWNER);
406 startActivity(intent);
407 showToast(R.string.provisioning_byod_delete_profile);
408 }
409 catch (ActivityNotFoundException e) {
410 Log.d(TAG, "requestDeleteProfileOwner: ActivityNotFoundException", e);
411 }
412 }
413
414 private void disableComponent() {
415 // Disable app components in the current profile, so only the counterpart in the other profile
416 // can respond (via cross-profile intent filter)
417 getPackageManager().setComponentEnabledSetting(new ComponentName(
418 this, ByodHelperActivity.class),
419 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
420 PackageManager.DONT_KILL_APP);
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000421 getPackageManager().setComponentEnabledSetting(new ComponentName(
422 this, WorkNotificationTestActivity.class),
423 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
424 PackageManager.DONT_KILL_APP);
Rubin Xu55d22d42014-09-24 19:56:58 +0100425 }
426
Rubin Xu55d22d42014-09-24 19:56:58 +0100427 private void showToast(int messageId) {
428 String message = getString(messageId);
429 Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
430 }
431
432 enum TestResult {
433 Unknown, Failed, Passed
434 }
435
436 static class TestItem {
437
438 private String mDisplayName;
439 private TestResult mPassed;
440 private boolean mManualTest;
441 private String mManualInstruction;
442 private Intent mManualIntent;
443
444 public TestItem(Context context, int nameResId) {
445 mDisplayName = context.getString(nameResId);
446 mPassed = TestResult.Unknown;
447 mManualTest = false;
448 }
449
450 public void performTest(ByodFlowTestActivity activity) {
451 if (isManualTest()) {
452 activity.showManualTestDialog(this);
453 }
454 }
455
456 public TestItem(Context context, int nameResId, int testInstructionResId, Intent testIntent) {
457 mDisplayName = context.getString(nameResId);
458 mPassed = TestResult.Unknown;
459 mManualTest = true;
460 mManualInstruction = context.getString(testInstructionResId);
461 mManualIntent = testIntent;
462 }
463
464 @Override
465 public String toString() {
466 return mDisplayName;
467 }
468
469 TestResult getPassFailState() {
470 return mPassed;
471 }
472
473 void setPassFailState(TestResult state) {
474 mPassed = state;
475 }
476
477 public boolean isManualTest() {
478 return mManualTest;
479 }
480
481 public String getManualTestInstruction() {
482 return mManualInstruction;
483 }
484
485 public Intent getManualTestIntent() {
486 return mManualIntent;
487 }
Alexandra Gherghina9c1c5a52014-12-09 12:55:23 +0000488
489 public View getCustomView() {
490 return null;
491 }
Rubin Xu55d22d42014-09-24 19:56:58 +0100492 }
493
Alexandra Gherghina2c672b72015-01-22 11:20:23 +0000494 static class TestItemWithIcon extends TestItem {
495
496 private int mImageResId;
497 private Context mContext;
498
499 public TestItemWithIcon(Context context, int nameResId, int testInstructionResId,
500 Intent testIntent, int imageResId) {
501 super(context, nameResId, testInstructionResId, testIntent);
502 mContext = context;
503 mImageResId = imageResId;
504 }
505
506 @Override
507 public View getCustomView() {
508 LayoutInflater layoutInflater = LayoutInflater.from(mContext);
509 View view = layoutInflater.inflate(R.layout.byod_custom_view,
510 null /* root */);
511 ((ImageView) view.findViewById(R.id.sample_icon)).setImageResource(mImageResId);
512 ((TextView) view.findViewById(R.id.message)).setText(getManualTestInstruction());
513 return view;
514 }
515 }
516
Rubin Xu55d22d42014-09-24 19:56:58 +0100517 static class TestAdapter extends ArrayAdapter<TestItem> {
518
519 public TestAdapter(Context context) {
520 super(context, android.R.layout.simple_list_item_1);
521 }
522
523 @Override
524 public View getView(int position, View convertView, ViewGroup parent) {
525 TextView view = (TextView) super.getView(position, convertView, parent);
526
527 TestItem item = getItem(position);
528 int backgroundResource = 0;
529 int iconResource = 0;
530 if (item.getPassFailState() == TestResult.Passed) {
531 backgroundResource = R.drawable.test_pass_gradient;
532 iconResource = R.drawable.fs_good;
533 } else if (item.getPassFailState() == TestResult.Failed){
534 backgroundResource = R.drawable.test_fail_gradient;
535 iconResource = R.drawable.fs_error;
536 }
537 view.setBackgroundResource(backgroundResource);
538 view.setPadding(10, 0, 10, 0);
539 view.setCompoundDrawablePadding(10);
540 view.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0);
541
542 return view;
543 }
544 }
Rubin Xu55d22d42014-09-24 19:56:58 +0100545}