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 com.android.systemui.qs.tiles.impl.qr.domain.interactor 18 19 import android.os.UserHandle 20 import com.android.systemui.dagger.qualifiers.Application 21 import com.android.systemui.dagger.qualifiers.Background 22 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController 23 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE 24 import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger 25 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor 26 import com.android.systemui.qs.tiles.impl.qr.domain.model.QRCodeScannerTileModel 27 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow 28 import javax.inject.Inject 29 import kotlin.coroutines.CoroutineContext 30 import kotlinx.coroutines.CoroutineScope 31 import kotlinx.coroutines.channels.awaitClose 32 import kotlinx.coroutines.flow.Flow 33 import kotlinx.coroutines.flow.SharingStarted 34 import kotlinx.coroutines.flow.flowOf 35 import kotlinx.coroutines.flow.flowOn 36 import kotlinx.coroutines.flow.onStart 37 import kotlinx.coroutines.flow.stateIn 38 39 /** Observes one qr scanner state changes providing the [QRCodeScannerTileModel]. */ 40 class QRCodeScannerTileDataInteractor 41 @Inject 42 constructor( 43 @Background private val bgCoroutineContext: CoroutineContext, 44 @Application private val scope: CoroutineScope, 45 private val qrController: QRCodeScannerController, 46 ) : QSTileDataInteractor<QRCodeScannerTileModel> { tileDatanull47 override fun tileData( 48 user: UserHandle, 49 triggers: Flow<DataUpdateTrigger> 50 ): Flow<QRCodeScannerTileModel> = 51 conflatedCallbackFlow { 52 qrController.registerQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE) 53 val callback = 54 object : QRCodeScannerController.Callback { 55 override fun onQRCodeScannerActivityChanged() { 56 trySend(generateModel()) 57 } 58 } 59 qrController.addCallback(callback) 60 awaitClose { 61 qrController.removeCallback(callback) 62 qrController.unregisterQRCodeScannerChangeObservers( 63 DEFAULT_QR_CODE_SCANNER_CHANGE 64 ) 65 } 66 } <lambda>null67 .onStart { emit(generateModel()) } 68 .flowOn(bgCoroutineContext) 69 .stateIn( 70 scope, 71 SharingStarted.WhileSubscribed(), 72 QRCodeScannerTileModel.TemporarilyUnavailable 73 ) 74 availabilitynull75 override fun availability(user: UserHandle): Flow<Boolean> = 76 flowOf(qrController.isCameraAvailable) 77 78 private fun generateModel(): QRCodeScannerTileModel { 79 val intent = qrController.intent 80 81 return if (qrController.isAbleToLaunchScannerActivity && intent != null) 82 QRCodeScannerTileModel.Available(intent) 83 else QRCodeScannerTileModel.TemporarilyUnavailable 84 } 85 } 86