1 /* 2 * Copyright (C) 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 * 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 17 package android.companion.cts.multidevice 18 19 import android.companion.AssociationInfo 20 import android.companion.CompanionDeviceManager 21 import android.companion.CompanionException 22 import android.content.IntentSender 23 import android.os.OutcomeReceiver 24 import android.security.attestationverification.VerificationToken 25 import java.util.concurrent.CountDownLatch 26 import java.util.concurrent.TimeUnit.SECONDS 27 import java.util.concurrent.TimeoutException 28 import java.util.concurrent.atomic.AtomicBoolean 29 import java.util.function.BiConsumer 30 31 /** Blocking callbacks for CDM callbacks. */ 32 object CallbackUtils { 33 private const val TAG = "CDM_CallbackUtils" 34 private const val CALLBACK_TIMEOUT_SEC = 30L 35 36 class AssociationCallback : CompanionDeviceManager.Callback() { 37 private val pending = CountDownLatch(1) 38 private val created = CountDownLatch(1) 39 40 private var pendingIntent: IntentSender? = null 41 private var associationInfo: AssociationInfo? = null 42 private var error: String? = null 43 onAssociationPendingnull44 override fun onAssociationPending(intentSender: IntentSender) { 45 this.pendingIntent = intentSender 46 pending.countDown() 47 } 48 onAssociationCreatednull49 override fun onAssociationCreated(associationInfo: AssociationInfo) { 50 this.associationInfo = associationInfo 51 created.countDown() 52 } 53 onFailurenull54 override fun onFailure(error: CharSequence?) { 55 this.error = error?.toString() ?: "There was an unexpected failure." 56 pending.countDown() 57 created.countDown() 58 } 59 waitForPendingIntentnull60 fun waitForPendingIntent(): IntentSender? { 61 if (!pending.await(CALLBACK_TIMEOUT_SEC, SECONDS)) { 62 throw TimeoutException("Pending association request timed out.") 63 } 64 65 error?.let { 66 throw RuntimeException(it) 67 } 68 69 return pendingIntent 70 } 71 waitForAssociationnull72 fun waitForAssociation(): AssociationInfo? { 73 if (!created.await(CALLBACK_TIMEOUT_SEC, SECONDS)) { 74 throw TimeoutException("Association request timed out.") 75 } 76 77 error?.let { 78 throw RuntimeException(it) 79 } 80 81 return associationInfo 82 } 83 } 84 85 class SystemDataTransferCallback : OutcomeReceiver<Void, CompanionException> { 86 private val completed = CountDownLatch(1) 87 88 private var error: CompanionException? = null 89 onResultnull90 override fun onResult(result: Void?) { 91 completed.countDown() 92 } 93 onErrornull94 override fun onError(error: CompanionException) { 95 this.error = error 96 completed.countDown() 97 } 98 waitForCompletionnull99 fun waitForCompletion() { 100 if (!completed.await(CALLBACK_TIMEOUT_SEC, SECONDS)) { 101 throw TimeoutException("System data transfer timed out.") 102 } 103 104 error?.let { 105 throw it 106 } 107 } 108 } 109 110 class AttestationVerificationCallback : BiConsumer<Int, VerificationToken?> { 111 private val completed = CountDownLatch(1) 112 private val result = AtomicBoolean(false) 113 acceptnull114 override fun accept(resultCode: Int, token: VerificationToken?) { 115 result.set(resultCode == 0) 116 completed.countDown() 117 } 118 waitForResultnull119 fun waitForResult(): Boolean { 120 if (!completed.await(CALLBACK_TIMEOUT_SEC, SECONDS)) { 121 throw TimeoutException("Attestation verification timed out.") 122 } 123 124 return result.get() 125 } 126 } 127 } 128