1 /*
2 * Copyright 2024 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 * https://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.devicediagnostics.evaluated
17
18 import android.app.Activity
19 import android.content.Intent
20 import android.os.Parcel
21 import android.os.Parcelable
22 import com.android.devicediagnostics.DiagnosticsActivity
23 import com.android.devicediagnostics.Protos.TestResults
24 import com.android.devicediagnostics.Protos.TrustedDeviceInfo
25
26 // When running through a trusted/evaluated test sequence, this key is used to communicate
27 // test state between activities.
28 private const val TEST_STATE_KEY = "test_state"
29
30 // Helper class for currying data between activities. This is only constructed when running
31 // multiple tests in succession.
32 class TestState(
33 var testResults: TestResults,
34 var trustedDevice: TrustedDeviceInfo,
35 ) : Parcelable {
36 constructor(
37 parcel: Parcel
38 ) : this(
39 testResults = TestResults.parseFrom(parcel.createByteArray()),
40 trustedDevice = TrustedDeviceInfo.parseFrom(parcel.createByteArray())
41 ) {}
42
writeToParcelnull43 override fun writeToParcel(dest: Parcel, flags: Int) {
44 dest.writeByteArray(testResults.toByteArray())
45 dest.writeByteArray(trustedDevice.toByteArray())
46 }
47
describeContentsnull48 override fun describeContents(): Int {
49 return 0
50 }
51
52 companion object CREATOR : Parcelable.Creator<TestState> {
createFromParcelnull53 override fun createFromParcel(parcel: Parcel): TestState {
54 return TestState(parcel)
55 }
56
newArraynull57 override fun newArray(size: Int): Array<TestState?> {
58 return arrayOfNulls(size)
59 }
60
fromActivitynull61 fun fromActivity(activity: Activity): TestState? {
62 return activity.intent.getParcelableExtra(TEST_STATE_KEY, TestState::class.java)
63 }
64 }
65 }
66
startFullTestFlownull67 fun startFullTestFlow(from: Activity, trustedDeviceInfo: TrustedDeviceInfo) {
68 nextTestActivity(from, ScreenTestIntroActivity::class.java.name) {
69 val results = TestResults.getDefaultInstance()
70 val state = TestState(results, trustedDeviceInfo)
71 it.putExtra(TEST_STATE_KEY, state)
72 }
73 }
74
75 // Advance through test subactivities (eg TouchTestIntro -> TouchTest).
nextTestActivitynull76 fun nextTestActivity(
77 from: Activity,
78 nextClass: String,
79 withIntent: ((intent: Intent) -> Unit)? = null
80 ) {
81 val intent = Intent()
82 intent.setClassName(from, nextClass)
83
84 val state = TestState.fromActivity(from)
85 if (state != null) intent.putExtra(TEST_STATE_KEY, state)
86 if (withIntent != null) withIntent(intent)
87
88 from.startActivity(intent)
89 }
90
91 // Advance to the next activity group in the test flow, concluding the current test.
nextTestnull92 fun nextTest(from: Activity, withReport: (builder: TestResults.Builder) -> Unit) {
93 if (isOneShotTest(from)) {
94 Intent(from, DiagnosticsActivity::class.java).also {
95 it.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
96 from.startActivity(it)
97 from.finish()
98 }
99 return
100 }
101
102 val state = TestState.fromActivity(from)!!
103 val builder = state.testResults.toBuilder()
104 if (withReport != null) withReport(builder)
105 state.testResults = builder.build()
106
107 val nextActivityClass =
108 when (from.javaClass.name) {
109 ScreenTestFinalizeActivity::class.java.name -> TouchTestIntroActivity::class.java.name
110 TouchTestFinalizeActivity::class.java.name ->
111 EvaluationFinalizeActivity::class.java.name
112 else -> null
113 }
114
115 val intent = Intent()
116 intent.setClassName(from, nextActivityClass!!)
117 intent.putExtra(TEST_STATE_KEY, state)
118
119 // Don't allow navigating back once we're submitting the results.
120 if (nextActivityClass == EvaluationFinalizeActivity::class.java.name)
121 intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)
122
123 from.startActivity(intent)
124 }
125
126 // Returns whether the current activity is part of one-shot test flow.
isOneShotTestnull127 fun isOneShotTest(from: Activity): Boolean {
128 val extras = from.intent.extras
129 if (extras == null) return true
130 return !extras.containsKey(TEST_STATE_KEY)
131 }
132