1 /* 2 * Copyright (C) 2016 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 package com.android.cts.verifier.vr; 17 18 import android.content.ComponentName; 19 import android.content.Intent; 20 import android.content.SharedPreferences; 21 import android.os.Bundle; 22 import android.os.Handler; 23 import android.os.HandlerThread; 24 import android.provider.Settings; 25 import android.util.Log; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.Button; 30 import android.widget.ImageView; 31 import android.widget.TextView; 32 33 34 import com.android.cts.verifier.PassFailButtons; 35 import com.android.cts.verifier.R; 36 37 import java.util.Arrays; 38 import java.util.Objects; 39 import java.util.concurrent.ArrayBlockingQueue; 40 import java.util.concurrent.Executors; 41 import java.util.concurrent.ScheduledExecutorService; 42 import java.util.concurrent.TimeUnit; 43 44 public class VrListenerVerifierActivity extends PassFailButtons.Activity { 45 46 private static final String TAG = "VrListenerActivity"; 47 public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners"; 48 private static final String STATE = "state"; 49 private static final int POLL_DELAY_MS = 2000; 50 static final String EXTRA_LAUNCH_SECOND_INTENT = "do2intents"; 51 52 private LayoutInflater mInflater; 53 private InteractiveTestCase[] mTests; 54 private ViewGroup mTestViews; 55 private int mCurrentIdx; 56 private Handler mMainHandler; 57 private Handler mTestHandler; 58 private HandlerThread mTestThread; 59 private PersistentTestStatusHandler persistentTestStatusHandler; 60 61 public enum Status { 62 SETUP, 63 RUNNING, 64 PASS, 65 FAIL, 66 WAIT_FOR_USER; 67 } 68 69 @Override onCreate(Bundle savedState)70 protected void onCreate(Bundle savedState) { 71 super.onCreate(savedState); 72 mCurrentIdx = (savedState == null) ? 0 : savedState.getInt(STATE, 0); 73 74 persistentTestStatusHandler = new PersistentTestStatusHandler(); 75 mTestThread = new HandlerThread("VrTestThread"); 76 mTestThread.start(); 77 mTestHandler = new Handler(mTestThread.getLooper()); 78 mInflater = getLayoutInflater(); 79 View v = mInflater.inflate(R.layout.vr_main, null); 80 setContentView(v); 81 setPassFailButtonClickListeners(); 82 getPassButton().setEnabled(false); 83 setInfoResources(R.string.vr_test_title, R.string.vr_info, -1); 84 85 mTestViews = (ViewGroup) v.findViewById(R.id.vr_test_items); 86 mTests = new InteractiveTestCase[] { 87 new IsDefaultDisabledTest(), 88 new UserEnableTest(), 89 new VrModeSwitchTest(), 90 new VrModeMultiSwitchTest(), 91 new UserDisableTest(), 92 }; 93 94 for (InteractiveTestCase test : mTests) { 95 test.setStatus((savedState == null) ? Status.SETUP : 96 Status.values()[savedState.getInt(test.getClass().getSimpleName(), 0)]); 97 mTestViews.addView(test.getView(mTestViews)); 98 } 99 100 updateUiState(); 101 102 mMainHandler = new Handler(); 103 } 104 105 @Override onDestroy()106 public void onDestroy() { 107 super.onDestroy(); 108 if (mTestThread != null) { 109 mTestThread.quit(); 110 } 111 } 112 113 @Override onSaveInstanceState(Bundle outState)114 protected void onSaveInstanceState(Bundle outState) { 115 outState.putInt(STATE, mCurrentIdx); 116 for (InteractiveTestCase i : mTests) { 117 outState.putInt(i.getClass().getSimpleName(), i.getStatus().ordinal()); 118 } 119 super.onSaveInstanceState(outState); 120 } 121 122 @Override onResume()123 protected void onResume() { 124 super.onResume(); 125 126 final InteractiveTestCase current = mTests[mCurrentIdx]; 127 final Status currentTestStatus = current.getStatus(); 128 if (currentTestStatus == Status.RUNNING) { 129 // The previous instance of this class was interurpted while a test 130 // was running most likely due to a configuration change 131 // We must wait for the previous test results to be written to the 132 // shared configuration file before continuing with the next test 133 waitForPreviousRunningTest(); 134 } else if (currentTestStatus == Status.PASS) { 135 // The previous instance of this class was interrupted after a test 136 // has finished running most likely due to a configuration change 137 selectNext(); 138 } else { 139 runNext(); 140 } 141 } 142 waitForPreviousRunningTest()143 private void waitForPreviousRunningTest() { 144 final InteractiveTestCase current = mTests[mCurrentIdx]; 145 ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor(); 146 147 s.scheduleAtFixedRate(new Runnable() { 148 private void handleTestFinished() { 149 selectNext(); 150 s.shutdown(); 151 } 152 153 @Override 154 public void run() { 155 Status status = persistentTestStatusHandler.getStatusOfTest(mCurrentIdx); 156 157 if (status == Status.PASS) { 158 current.markPassed(); 159 handleTestFinished(); 160 } else if (status == Status.FAIL) { 161 current.markFailed(); 162 handleTestFinished(); 163 } 164 } 165 }, 0, POLL_DELAY_MS, TimeUnit.MILLISECONDS); 166 } 167 updateUiState()168 private void updateUiState() { 169 boolean allPassed = true; 170 for (InteractiveTestCase t : mTests) { 171 t.updateViews(); 172 if (t.getStatus() != Status.PASS) { 173 allPassed = false; 174 } 175 } 176 177 if (allPassed) { 178 getPassButton().setEnabled(true); 179 } 180 } 181 logWithStack(String message)182 protected void logWithStack(String message) { 183 logWithStack(message, null); 184 } 185 logWithStack(String message, Throwable stackTrace)186 protected void logWithStack(String message, Throwable stackTrace) { 187 if (stackTrace == null) { 188 stackTrace = new Throwable(); 189 stackTrace.fillInStackTrace(); 190 } 191 Log.e(TAG, message, stackTrace); 192 } 193 selectNext()194 private void selectNext() { 195 mCurrentIdx++; 196 if (mCurrentIdx >= mTests.length) { 197 done(); 198 return; 199 } 200 final InteractiveTestCase current = mTests[mCurrentIdx]; 201 current.markWaiting(); 202 } 203 runNext()204 private void runNext() { 205 if (mCurrentIdx >= mTests.length) { 206 done(); 207 return; 208 } 209 final InteractiveTestCase current = mTests[mCurrentIdx]; 210 mTestHandler.post(new Runnable() { 211 @Override 212 public void run() { 213 Log.i(TAG, "Starting test: " + current.getClass().getSimpleName()); 214 persistentTestStatusHandler.setStatusOfTest(mCurrentIdx, Status.RUNNING); 215 boolean passed = true; 216 try { 217 current.setUp(); 218 current.test(); 219 } catch (Throwable e) { 220 logWithStack("Failed " + current.getClass().getSimpleName() + " with: ", e); 221 setFailed(current); 222 passed = false; 223 } finally { 224 try { 225 current.tearDown(); 226 } catch (Throwable e) { 227 logWithStack("Failed tearDown of " + current.getClass().getSimpleName() + 228 " with: ", e); 229 setFailed(current); 230 passed = false; 231 } 232 } 233 234 // Write to persistent store in the event that the activity was 235 // destroyed while this test was running 236 persistentTestStatusHandler.setStatusOfTest(mCurrentIdx, passed ? Status.PASS : Status.FAIL); 237 238 if (passed) { 239 current.markPassed(); 240 mMainHandler.post(new Runnable() { 241 @Override 242 public void run() { 243 selectNext(); 244 } 245 }); 246 } 247 Log.i(TAG, "Done test: " + current.getClass().getSimpleName()); 248 } 249 }); 250 } 251 done()252 private void done() { 253 updateUiState(); 254 persistentTestStatusHandler.clear(); 255 Log.i(TAG, "Completed run!"); 256 } 257 258 setFailed(final InteractiveTestCase current)259 private void setFailed(final InteractiveTestCase current) { 260 mMainHandler.post(new Runnable() { 261 @Override 262 public void run() { 263 getPassButton().setEnabled(false); 264 current.markFailed(); 265 } 266 }); 267 } 268 createUserInteractionTestView(ViewGroup parent, int stringId, int messageId)269 protected View createUserInteractionTestView(ViewGroup parent, int stringId, int messageId) { 270 View v = mInflater.inflate(R.layout.vr_item, parent, false); 271 TextView instructions = (TextView) v.findViewById(R.id.vr_instructions); 272 instructions.setText(getString(messageId)); 273 Button b = (Button) v.findViewById(R.id.vr_action_button); 274 b.setText(stringId); 275 b.setTag(stringId); 276 return v; 277 } 278 createAutoTestView(ViewGroup parent, int messageId)279 protected View createAutoTestView(ViewGroup parent, int messageId) { 280 View v = mInflater.inflate(R.layout.vr_item, parent, false); 281 TextView instructions = (TextView) v.findViewById(R.id.vr_instructions); 282 instructions.setText(getString(messageId)); 283 Button b = (Button) v.findViewById(R.id.vr_action_button); 284 b.setVisibility(View.GONE); 285 return v; 286 } 287 288 protected abstract class InteractiveTestCase { 289 protected static final String TAG = "InteractiveTest"; 290 private Status status; 291 private View view; 292 inflate(ViewGroup parent)293 abstract View inflate(ViewGroup parent); 294 getView(ViewGroup parent)295 View getView(ViewGroup parent) { 296 if (view == null) { 297 view = inflate(parent); 298 } 299 return view; 300 } 301 test()302 abstract void test() throws Throwable; 303 setUp()304 void setUp() throws Throwable { 305 // Noop 306 } 307 tearDown()308 void tearDown() throws Throwable { 309 // Noop 310 } 311 getStatus()312 Status getStatus() { 313 return status; 314 } 315 setStatus(Status s)316 void setStatus(Status s) { 317 status = s; 318 } 319 markFailed()320 void markFailed() { 321 Log.i(TAG, "FAILED test: " + this.getClass().getSimpleName()); 322 mMainHandler.post(new Runnable() { 323 @Override 324 public void run() { 325 InteractiveTestCase.this.setStatus(Status.FAIL); 326 updateViews(); 327 } 328 }); 329 } 330 markPassed()331 void markPassed() { 332 Log.i(TAG, "PASSED test: " + this.getClass().getSimpleName()); 333 mMainHandler.post(new Runnable() { 334 @Override 335 public void run() { 336 InteractiveTestCase.this.setStatus(Status.PASS); 337 updateViews(); 338 } 339 }); 340 } 341 markFocused()342 void markFocused() { 343 mMainHandler.post(new Runnable() { 344 @Override 345 public void run() { 346 InteractiveTestCase.this.setStatus(Status.SETUP); 347 updateViews(); 348 } 349 }); 350 } 351 markWaiting()352 void markWaiting() { 353 mMainHandler.post(new Runnable() { 354 @Override 355 public void run() { 356 InteractiveTestCase.this.setStatus(Status.WAIT_FOR_USER); 357 updateViews(); 358 } 359 }); 360 } 361 markRunning()362 void markRunning() { 363 mMainHandler.post(new Runnable() { 364 @Override 365 public void run() { 366 InteractiveTestCase.this.setStatus(Status.RUNNING); 367 updateViews(); 368 } 369 }); 370 } 371 updateViews()372 private void updateViews() { 373 View item = view; 374 ImageView statusView = (ImageView) item.findViewById(R.id.vr_status); 375 View button = item.findViewById(R.id.vr_action_button); 376 switch (status) { 377 case WAIT_FOR_USER: 378 statusView.setImageResource(R.drawable.fs_warning); 379 button.setEnabled(true); 380 break; 381 case SETUP: 382 statusView.setImageResource(R.drawable.fs_indeterminate); 383 button.setEnabled(false); 384 break; 385 case RUNNING: 386 statusView.setImageResource(R.drawable.fs_clock); 387 break; 388 case FAIL: 389 statusView.setImageResource(R.drawable.fs_error); 390 break; 391 case PASS: 392 statusView.setImageResource(R.drawable.fs_good); 393 button.setClickable(false); 394 button.setEnabled(false); 395 break; 396 } 397 statusView.invalidate(); 398 } 399 } 400 assertTrue(String message, boolean b)401 private static void assertTrue(String message, boolean b) { 402 if (!b) { 403 throw new IllegalStateException(message); 404 } 405 } 406 assertIn(String message, E elem, E[] c)407 private static <E> void assertIn(String message, E elem, E[] c) { 408 if (!Arrays.asList(c).contains(elem)) { 409 throw new IllegalStateException(message); 410 } 411 } 412 assertEventIn(String message, MockVrListenerService.Event elem, MockVrListenerService.EventType[] c)413 private static void assertEventIn(String message, MockVrListenerService.Event elem, 414 MockVrListenerService.EventType[] c) { 415 if (!Arrays.asList(c).contains(elem.type)) { 416 throw new IllegalStateException(message); 417 } 418 } 419 launchVrListenerSettings()420 protected void launchVrListenerSettings() { 421 VrListenerVerifierActivity.this.startActivity( 422 new Intent(Settings.ACTION_VR_LISTENER_SETTINGS)); 423 } 424 launchVrActivity()425 protected void launchVrActivity() { 426 VrListenerVerifierActivity.this.startActivity( 427 new Intent(VrListenerVerifierActivity.this, MockVrActivity.class)); 428 } 429 launchDoubleVrActivity()430 protected void launchDoubleVrActivity() { 431 VrListenerVerifierActivity.this.startActivity( 432 new Intent(VrListenerVerifierActivity.this, MockVrActivity.class). 433 putExtra(EXTRA_LAUNCH_SECOND_INTENT, true)); 434 } 435 actionPressed(View v)436 public void actionPressed(View v) { 437 Object tag = v.getTag(); 438 if (tag instanceof Integer) { 439 int id = ((Integer) tag).intValue(); 440 if (id == R.string.vr_start_settings) { 441 launchVrListenerSettings(); 442 } else if (id == R.string.vr_start_vr_activity) { 443 launchVrActivity(); 444 } else if (id == R.string.vr_start_double_vr_activity) { 445 launchDoubleVrActivity(); 446 } 447 } 448 } 449 450 private class IsDefaultDisabledTest extends InteractiveTestCase { 451 452 @Override inflate(ViewGroup parent)453 View inflate(ViewGroup parent) { 454 return createAutoTestView(parent, R.string.vr_check_disabled); 455 } 456 457 @Override setUp()458 void setUp() { 459 markFocused(); 460 } 461 462 @Override test()463 void test() { 464 assertTrue("VR listeners should not be bound by default.", 465 MockVrListenerService.getNumBoundMockVrListeners() == 0); 466 } 467 } 468 469 private class UserEnableTest extends InteractiveTestCase { 470 471 @Override inflate(ViewGroup parent)472 View inflate(ViewGroup parent) { 473 return createUserInteractionTestView(parent, R.string.vr_start_settings, 474 R.string.vr_enable_service); 475 } 476 477 @Override setUp()478 void setUp() { 479 markWaiting(); 480 } 481 482 @Override test()483 void test() { 484 String helpers = Settings.Secure.getString(getContentResolver(), ENABLED_VR_LISTENERS); 485 ComponentName c = new ComponentName(VrListenerVerifierActivity.this, 486 MockVrListenerService.class); 487 if (MockVrListenerService.getPendingEvents().size() > 0) { 488 MockVrListenerService.getPendingEvents().clear(); 489 throw new IllegalStateException("VrListenerService bound before entering VR mode!"); 490 } 491 assertTrue("Settings must now contain " + c.flattenToString(), 492 helpers != null && helpers.contains(c.flattenToString())); 493 } 494 } 495 496 private class VrModeSwitchTest extends InteractiveTestCase { 497 498 @Override inflate(ViewGroup parent)499 View inflate(ViewGroup parent) { 500 return createUserInteractionTestView(parent, R.string.vr_start_vr_activity, 501 R.string.vr_start_vr_activity_desc); 502 } 503 504 @Override setUp()505 void setUp() { 506 markWaiting(); 507 } 508 509 @Override test()510 void test() throws Throwable { 511 markRunning(); 512 513 ArrayBlockingQueue<MockVrListenerService.Event> q = 514 MockVrListenerService.getPendingEvents(); 515 MockVrListenerService.Event e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 516 assertTrue("Timed out before receive onCreate or onBind event from VrListenerService.", 517 e != null); 518 assertEventIn("First listener service event must be onCreate or onBind, but was " + 519 e.type, e, new MockVrListenerService.EventType[]{ 520 MockVrListenerService.EventType.ONCREATE, 521 MockVrListenerService.EventType.ONBIND 522 }); 523 if (e.type == MockVrListenerService.EventType.ONCREATE) { 524 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 525 assertTrue("Timed out before receive onBind event from VrListenerService.", 526 e != null); 527 assertEventIn("Second listener service event must be onBind, but was " + 528 e.type, e, new MockVrListenerService.EventType[]{ 529 MockVrListenerService.EventType.ONBIND 530 }); 531 } 532 533 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 534 assertTrue("Timed out before receive onCurrentVrModeActivityChanged event " + 535 "from VrListenerService.", e != null); 536 assertTrue("Listener service must receive onCurrentVrModeActivityChanged, but was " + 537 e.type, 538 e.type == MockVrListenerService.EventType.ONCURRENTVRMODEACTIVITYCHANGED); 539 ComponentName expected = new ComponentName(VrListenerVerifierActivity.this, 540 MockVrActivity.class); 541 assertTrue("Activity component must be " + expected + ", but was: " + e.arg1, 542 Objects.equals(expected, e.arg1)); 543 544 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 545 assertTrue("Timed out before receive unbind event from VrListenerService.", e != null); 546 assertEventIn("Listener service must receive onUnbind, but was " + 547 e.type, e, new MockVrListenerService.EventType[]{ 548 MockVrListenerService.EventType.ONUNBIND 549 }); 550 551 // Consume onDestroy 552 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 553 assertTrue("Timed out before receive onDestroy event from VrListenerService.", 554 e != null); 555 assertEventIn("Listener service must receive onDestroy, but was " + 556 e.type, e, new MockVrListenerService.EventType[]{ 557 MockVrListenerService.EventType.ONDESTROY 558 }); 559 560 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 561 if (e != null) { 562 throw new IllegalStateException("Spurious event received after onDestroy: " 563 + e.type); 564 } 565 } 566 } 567 568 private class VrModeMultiSwitchTest extends InteractiveTestCase { 569 570 @Override inflate(ViewGroup parent)571 View inflate(ViewGroup parent) { 572 return createUserInteractionTestView(parent, R.string.vr_start_double_vr_activity, 573 R.string.vr_start_vr_double_activity_desc); 574 } 575 576 @Override setUp()577 void setUp() { 578 markWaiting(); 579 } 580 581 @Override test()582 void test() throws Throwable { 583 markRunning(); 584 585 ArrayBlockingQueue<MockVrListenerService.Event> q = 586 MockVrListenerService.getPendingEvents(); 587 MockVrListenerService.Event e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 588 assertTrue("Timed out before receive event from VrListenerService.", e != null); 589 assertEventIn("First listener service event must be onCreate or onBind, but was " + 590 e.type, e, new MockVrListenerService.EventType[]{ 591 MockVrListenerService.EventType.ONCREATE, 592 MockVrListenerService.EventType.ONBIND 593 }); 594 if (e.type == MockVrListenerService.EventType.ONCREATE) { 595 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 596 assertTrue("Timed out before receive event from VrListenerService.", e != null); 597 assertEventIn("Second listener service event must be onBind, but was " + 598 e.type, e, new MockVrListenerService.EventType[]{ 599 MockVrListenerService.EventType.ONBIND 600 }); 601 } 602 603 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 604 assertTrue("Timed out before receive event from VrListenerService.", e != null); 605 assertTrue("Listener service must receive onCurrentVrModeActivityChanged, but received " 606 + e.type, e.type == 607 MockVrListenerService.EventType.ONCURRENTVRMODEACTIVITYCHANGED); 608 ComponentName expected = new ComponentName(VrListenerVerifierActivity.this, 609 MockVrActivity.class); 610 assertTrue("Activity component must be " + expected + ", but was: " + e.arg1, 611 Objects.equals(expected, e.arg1)); 612 613 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 614 assertTrue("Timed out before receive event from VrListenerService.", e != null); 615 assertTrue("Listener service must receive onCurrentVrModeActivityChanged, but received " 616 + e.type, e.type == 617 MockVrListenerService.EventType.ONCURRENTVRMODEACTIVITYCHANGED); 618 ComponentName expected2 = new ComponentName(VrListenerVerifierActivity.this, 619 MockVrActivity2.class); 620 assertTrue("Activity component must be " + expected2 + ", but was: " + e.arg1, 621 Objects.equals(expected2, e.arg1)); 622 623 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 624 assertTrue("Timed out before receive event from VrListenerService.", e != null); 625 assertTrue("Listener service must receive onCurrentVrModeActivityChanged, but received " 626 + e.type, e.type == 627 MockVrListenerService.EventType.ONCURRENTVRMODEACTIVITYCHANGED); 628 assertTrue("Activity component must be " + expected + ", but was: " + e.arg1, 629 Objects.equals(expected, e.arg1)); 630 631 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 632 assertTrue("Timed out before receive event from VrListenerService.", e != null); 633 assertEventIn("Listener service must receive onUnbind, but was " + 634 e.type, e, new MockVrListenerService.EventType[]{ 635 MockVrListenerService.EventType.ONUNBIND 636 }); 637 638 // Consume onDestroy 639 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 640 assertTrue("Timed out before receive onDestroy event from VrListenerService.", 641 e != null); 642 assertEventIn("Listener service must receive onDestroy, but was " + 643 e.type, e, new MockVrListenerService.EventType[]{ 644 MockVrListenerService.EventType.ONDESTROY 645 }); 646 647 e = q.poll(POLL_DELAY_MS, TimeUnit.MILLISECONDS); 648 if (e != null) { 649 throw new IllegalStateException("Spurious event received after onDestroy: " 650 + e.type); 651 } 652 } 653 } 654 655 private class UserDisableTest extends InteractiveTestCase { 656 657 @Override inflate(ViewGroup parent)658 View inflate(ViewGroup parent) { 659 return createUserInteractionTestView(parent, R.string.vr_start_settings, 660 R.string.vr_disable_service); 661 } 662 663 @Override setUp()664 void setUp() { 665 markWaiting(); 666 } 667 668 @Override test()669 void test() { 670 String helpers = Settings.Secure.getString(getContentResolver(), ENABLED_VR_LISTENERS); 671 ComponentName c = new ComponentName(VrListenerVerifierActivity.this, 672 MockVrListenerService.class); 673 assertTrue("Settings must no longer contain " + c.flattenToString(), 674 helpers == null || !(helpers.contains(c.flattenToString()))); 675 } 676 } 677 678 private class PersistentTestStatusHandler { 679 680 private final String PREFERENCE_FILE_NAME = "VrListenerVerifierActivityTestStatus"; 681 private final SharedPreferences sharedPref = getSharedPreferences(PREFERENCE_FILE_NAME, 0); 682 getStatusOfTest(int testIndex)683 Status getStatusOfTest(int testIndex) { 684 String key = Integer.toString(testIndex); 685 String stringStatus = sharedPref.getString(key, Status.WAIT_FOR_USER.name()); 686 687 return Status.valueOf(stringStatus); 688 } 689 setStatusOfTest(int testIndex, Status status)690 void setStatusOfTest(int testIndex, Status status) { 691 String key = Integer.toString(testIndex); 692 String stringStatus = status.name(); 693 694 SharedPreferences.Editor editor = sharedPref.edit(); 695 editor.putString(key, stringStatus); 696 editor.apply(); 697 } 698 clear()699 void clear() { 700 SharedPreferences.Editor editor = sharedPref.edit(); 701 editor.clear(); 702 editor.apply(); 703 } 704 } 705 } 706