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 18 19 import android.accessibilityservice.AccessibilityServiceInfo 20 import android.content.Context 21 import android.os.Build 22 import android.os.SystemProperties 23 import android.view.accessibility.AccessibilityManager 24 import com.android.devicediagnostics.bluetooth.BluetoothClient 25 import com.android.devicediagnostics.bluetooth.BluetoothClientImpl 26 import com.android.devicediagnostics.bluetooth.BluetoothServer 27 import com.android.devicediagnostics.bluetooth.FakeBluetoothClient 28 import com.android.settingslib.qrcode.QrCamera 29 import com.google.android.attestation.ParsedAttestationRecord 30 import kotlin.math.min 31 import kotlin.random.Random 32 33 open class ApplicationInterface { 34 private val btClient = BluetoothClientImpl() 35 private val btServer = BluetoothServer() 36 private var singleDeviceMode = false 37 getRandomBytesnull38 open fun getRandomBytes(count: Int): ByteArray { 39 return Random.nextBytes(count) 40 } 41 getQrCameranull42 open fun getQrCamera(context: Context, activity: QrCamera.ScannerCallback): QrCamera { 43 return QrCamera(context, activity) 44 } 45 getBluetoothClientnull46 open fun getBluetoothClient(): BluetoothClient { 47 if (singleDeviceMode) { 48 return FakeBluetoothClient() 49 } 50 return btClient 51 } 52 getBluetoothServernull53 open fun getBluetoothServer(): BluetoothServer { 54 return btServer 55 } 56 verifyAttestationnull57 open fun verifyAttestation( 58 attestation: ByteArray, 59 challenge: ByteArray, 60 ): Pair<ParsedAttestationRecord?, AttestationResult> { 61 return checkAttestation(attestation, challenge) 62 } 63 getLaunchLevelnull64 open fun getLaunchLevel(): Int { 65 val vendorApiLevel = getPropertyInt("ro.vendor.api_level", -1) 66 if (vendorApiLevel != -1) { 67 return vendorApiLevel 68 } 69 val boardApiLevel = getPropertyInt("ro.board.api_level", -1) 70 val firstApiLevel = getPropertyInt("ro.product.first_api_level", -1) 71 if (boardApiLevel != -1) { 72 if (firstApiLevel != -1) { 73 return min(boardApiLevel, firstApiLevel) 74 } 75 return boardApiLevel 76 } 77 return firstApiLevel 78 } 79 isUsingScreenReadernull80 open fun isUsingScreenReader(context: Context): Boolean { 81 val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager? 82 if (am == null || !am.isEnabled) { 83 return false 84 } 85 val serviceInfoList = 86 am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN) 87 return serviceInfoList.isNotEmpty() || am.isTouchExplorationEnabled 88 } 89 getPropertyIntnull90 private fun getPropertyInt(key: String, defaultValue: Int): Int { 91 var value: String? = null 92 value = SystemProperties.get(key, null) 93 if (value == null) { 94 return defaultValue 95 } 96 return try { 97 Integer.parseInt(value) 98 } catch (e: Exception) { 99 defaultValue 100 } 101 } 102 103 // This allows testing the Bluetooth flow without having two devices. enterSingleDeviceModenull104 fun enterSingleDeviceMode(): Boolean { 105 if (Build.IS_USER) { 106 return false 107 } 108 singleDeviceMode = true 109 return true 110 } 111 leaveSingleDeviceModenull112 fun leaveSingleDeviceMode() { 113 singleDeviceMode = false 114 } 115 116 companion object { 117 private var singleton = ApplicationInterface() 118 119 val app 120 get() = singleton 121 setAppnull122 fun setApp(app: ApplicationInterface) { 123 this.singleton = app 124 } 125 } 126 } 127