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 import com.google.protobuf.ByteString 39 40 private const val TAG = "EvaluationFinalize" 41 42 class EvaluationFinalizeFragment(private val ok: Boolean) : PreferenceFragmentCompat() { onCreatePreferencesnull43 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 44 setPreferencesFromResource(R.xml.preferences_evaluated_done, rootKey) 45 findPreference<Preference>("Done")!!.also { 46 if (!ok) { 47 it.setTitle(R.string.bluetooth_error_title) 48 it.setSummary(R.string.bluetooth_error_summary) 49 } 50 it.setOnPreferenceClickListener { 51 val intent = Intent(activity, MainActivity::class.java) 52 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 53 activity!!.startActivity(intent) 54 activity!!.finish() 55 true 56 } 57 } 58 } 59 } 60 61 class EvaluationFinalizeActivity : CollapsingToolbarBaseActivity() { onCreatenull62 override fun onCreate(savedInstanceState: Bundle?) { 63 super.onCreate(savedInstanceState) 64 setContentView(R.layout.evaluated_finalize) 65 setTitle(R.string.evaluation_mode_title) 66 67 if (savedInstanceState == null) { 68 showProgressIndicator(R.string.evaluated_finalizing_report) 69 buildReport() 70 } 71 } 72 buildReportnull73 private fun buildReport() { 74 val state = TestState.fromActivity(this)!! 75 76 // Launch in separate thread since gathering attestation takes time and we don't want to 77 // block the UI from appearing 78 runInBackground { 79 val reportBuilder = DeviceReport.newBuilder() 80 81 reportBuilder.setTests(state.testResults) 82 83 val batteryInfo = getBatteryInfo(this) 84 val storageInfo = getStorageInfo(this) 85 val launchLevel = ApplicationInterface.app.getLaunchLevel() 86 87 val attestation = createAttestationRecord(state.trustedDevice.challenge.toByteArray()) 88 reportBuilder.setAttestation(ByteString.copyFrom(attestation)) 89 reportBuilder.setBattery(batteryInfo) 90 reportBuilder.setStorage(storageInfo) 91 reportBuilder.setLaunchLevel(launchLevel) 92 93 val report = reportBuilder.build() 94 95 runOnUiThread { onReportReady(report) } 96 } 97 } 98 onReportReadynull99 private fun onReportReady(report: DeviceReport) { 100 val confirmation = showHeaderLayout(R.layout.evaluated_final_confirmation) 101 val button = confirmation.findViewById<Button>(R.id.send_button) 102 button!!.setOnClickListener { 103 sendReport(report) 104 true 105 } 106 107 val state = TestState.fromActivity(this)!! 108 val attestationController = 109 AttestationController(state.trustedDevice.challenge.toByteArray(), true) 110 111 supportFragmentManager.commit { 112 setReorderingAllowed(true) 113 replace( 114 R.id.fragment_container_view, 115 DisplayResultFragment(report, attestationController) 116 ) 117 } 118 } 119 sendReportnull120 private fun sendReport(report: DeviceReport) { 121 showProgressIndicator(R.string.sending_report) 122 123 runInBackground { 124 val bluetoothClient = ApplicationInterface.app.getBluetoothClient() 125 try { 126 bluetoothClient.sendReport(report) 127 runOnUiThread { onReportSent(true) } 128 } catch (e: Exception) { 129 Log.e(TAG, "Bluetooth error: $e") 130 runOnUiThread { onReportSent(false) } 131 } 132 } 133 134 supportFragmentManager.commit { 135 hide(supportFragmentManager.findFragmentById(R.id.fragment_container_view)!!) 136 } 137 } 138 onReportSentnull139 private fun onReportSent(sent: Boolean) { 140 hideHeaderLayout() 141 supportFragmentManager.commit { 142 replace(R.id.fragment_container_view, EvaluationFinalizeFragment(sent)) 143 } 144 } 145 showHeaderLayoutnull146 private fun showHeaderLayout(layoutId: Int): View { 147 val inflater = LayoutInflater.from(this) 148 val container = findViewById<LinearLayout>(R.id.header_container)!! 149 150 val view = inflater.inflate(layoutId, container, false) 151 152 container.removeAllViews() 153 container.addView(view) 154 container.visibility = View.VISIBLE 155 return view 156 } 157 hideHeaderLayoutnull158 private fun hideHeaderLayout() { 159 val container = findViewById<LinearLayout>(R.id.header_container)!! 160 container.visibility = View.GONE 161 } 162 showProgressIndicatornull163 private fun showProgressIndicator(stringResId: Int) { 164 val progress = showHeaderLayout(R.layout.progress_indicator) 165 val text = progress.findViewById<TextView>(R.id.progress_explainer) 166 text!!.setText(stringResId) 167 } 168 } 169