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 17 package com.android.devicediagnostics.evaluated 18 19 import android.content.Intent 20 import android.os.Bundle 21 import android.util.Log 22 import android.view.LayoutInflater 23 import android.view.View 24 import android.widget.Button 25 import android.widget.LinearLayout 26 import android.widget.TextView 27 import androidx.fragment.app.commit 28 import androidx.preference.Preference 29 import androidx.preference.PreferenceFragmentCompat 30 import com.android.devicediagnostics.ApplicationInterface 31 import com.android.devicediagnostics.AttestationController 32 import com.android.devicediagnostics.DisplayResultFragment 33 import com.android.devicediagnostics.MainActivity 34 import com.android.devicediagnostics.Protos.DeviceReport 35 import com.android.devicediagnostics.R 36 import com.android.devicediagnostics.runInBackground 37 import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity 38 39 private const val TAG = "EvaluationFinalize" 40 41 class EvaluationFinalizeFragment(private val ok: Boolean) : PreferenceFragmentCompat() { onCreatePreferencesnull42 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 43 setPreferencesFromResource(R.xml.preferences_evaluated_done, rootKey) 44 findPreference<Preference>("Done")!!.also { 45 if (!ok) { 46 it.setTitle(R.string.bluetooth_error_title) 47 it.setSummary(R.string.bluetooth_error_summary) 48 } 49 it.setOnPreferenceClickListener { 50 val intent = Intent(activity, MainActivity::class.java) 51 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 52 activity!!.startActivity(intent) 53 activity!!.finish() 54 true 55 } 56 } 57 } 58 } 59 60 class EvaluationFinalizeActivity : CollapsingToolbarBaseActivity() { onCreatenull61 override fun onCreate(savedInstanceState: Bundle?) { 62 super.onCreate(savedInstanceState) 63 setContentView(R.layout.evaluated_finalize) 64 setTitle(R.string.evaluation_mode_title) 65 66 if (savedInstanceState == null) { 67 showProgressIndicator(R.string.evaluated_finalizing_report) 68 buildReport() 69 } 70 } 71 buildReportnull72 private fun buildReport() { 73 val state = TestState.fromActivity(this)!! 74 75 // Launch in separate thread since gathering attestation takes time and we don't want to 76 // block the UI from appearing 77 runInBackground { 78 val reportBuilder = DeviceReport.newBuilder() 79 80 reportBuilder.setTests(state.testResults) 81 82 val batteryInfo = getBatteryInfo(this) 83 val storageInfo = getStorageInfo(this) 84 val launchLevel = ApplicationInterface.app.getLaunchLevel() 85 86 val attestation = createAttestationRecord(state.trustedDevice.challenge.toByteArray()) 87 88 val bluetoothClient = ApplicationInterface.app.getBluetoothClient() 89 val connectionData = bluetoothClient.connectionData 90 if (connectionData != null && connectionData.version == 4) { 91 reportBuilder.setOldAttestation(attestation.certificates) 92 } else { 93 reportBuilder.setAttestation(attestation) 94 } 95 96 reportBuilder.setBattery(batteryInfo) 97 reportBuilder.setStorage(storageInfo) 98 reportBuilder.setLaunchLevel(launchLevel) 99 100 val report = reportBuilder.build() 101 102 runOnUiThread { onReportReady(report) } 103 } 104 } 105 onReportReadynull106 private fun onReportReady(report: DeviceReport) { 107 val confirmation = showHeaderLayout(R.layout.evaluated_final_confirmation) 108 val button = confirmation.findViewById<Button>(R.id.send_button) 109 button!!.setOnClickListener { 110 sendReport(report) 111 true 112 } 113 114 val state = TestState.fromActivity(this)!! 115 val attestationController = 116 AttestationController(state.trustedDevice.challenge.toByteArray(), true) 117 118 supportFragmentManager.commit { 119 setReorderingAllowed(true) 120 replace( 121 R.id.fragment_container_view, 122 DisplayResultFragment(report, attestationController), 123 ) 124 } 125 } 126 sendReportnull127 private fun sendReport(report: DeviceReport) { 128 showProgressIndicator(R.string.sending_report) 129 130 runInBackground { 131 val bluetoothClient = ApplicationInterface.app.getBluetoothClient() 132 try { 133 bluetoothClient.sendReport(report) 134 runOnUiThread { onReportSent(true) } 135 } catch (e: Exception) { 136 Log.e(TAG, "Bluetooth error: $e") 137 runOnUiThread { onReportSent(false) } 138 } 139 } 140 141 supportFragmentManager.commit { 142 hide(supportFragmentManager.findFragmentById(R.id.fragment_container_view)!!) 143 } 144 } 145 onReportSentnull146 private fun onReportSent(sent: Boolean) { 147 hideHeaderLayout() 148 supportFragmentManager.commit { 149 replace(R.id.fragment_container_view, EvaluationFinalizeFragment(sent)) 150 } 151 } 152 showHeaderLayoutnull153 private fun showHeaderLayout(layoutId: Int): View { 154 val inflater = LayoutInflater.from(this) 155 val container = findViewById<LinearLayout>(R.id.header_container)!! 156 157 val view = inflater.inflate(layoutId, container, false) 158 159 container.removeAllViews() 160 container.addView(view) 161 container.visibility = View.VISIBLE 162 return view 163 } 164 hideHeaderLayoutnull165 private fun hideHeaderLayout() { 166 val container = findViewById<LinearLayout>(R.id.header_container)!! 167 container.visibility = View.GONE 168 } 169 showProgressIndicatornull170 private fun showProgressIndicator(stringResId: Int) { 171 val progress = showHeaderLayout(R.layout.progress_indicator) 172 val text = progress.findViewById<TextView>(R.id.progress_explainer) 173 text!!.setText(stringResId) 174 } 175 } 176