1 /* <lambda>null2 * Copyright (C) 2022 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 18 package com.android.systemui.keyguard.ui.preview 19 20 import android.os.Bundle 21 import android.os.Handler 22 import android.os.IBinder 23 import android.os.Message 24 import android.os.Messenger 25 import android.util.ArrayMap 26 import android.util.Log 27 import androidx.annotation.VisibleForTesting 28 import com.android.systemui.dagger.SysUISingleton 29 import com.android.systemui.dagger.qualifiers.Application 30 import com.android.systemui.dagger.qualifiers.Background 31 import com.android.systemui.dagger.qualifiers.Main 32 import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants 33 import javax.inject.Inject 34 import kotlinx.coroutines.CoroutineDispatcher 35 import kotlinx.coroutines.CoroutineScope 36 import kotlinx.coroutines.launch 37 38 @SysUISingleton 39 class KeyguardRemotePreviewManager 40 @Inject 41 constructor( 42 private val previewRendererFactory: KeyguardPreviewRendererFactory, 43 @Application private val applicationScope: CoroutineScope, 44 @Main private val mainDispatcher: CoroutineDispatcher, 45 @Background private val backgroundHandler: Handler, 46 ) { 47 private val activePreviews: ArrayMap<IBinder, PreviewLifecycleObserver> = 48 ArrayMap<IBinder, PreviewLifecycleObserver>() 49 50 fun preview(request: Bundle?): Bundle? { 51 if (request == null) { 52 return null 53 } 54 55 var observer: PreviewLifecycleObserver? = null 56 return try { 57 val renderer = previewRendererFactory.create(request) 58 59 // Destroy any previous renderer associated with this token. 60 activePreviews[renderer.hostToken]?.let { destroyObserver(it) } 61 observer = 62 PreviewLifecycleObserver( 63 renderer, 64 applicationScope, 65 mainDispatcher, 66 ::destroyObserver, 67 ) 68 activePreviews[renderer.hostToken] = observer 69 renderer.render() 70 renderer.hostToken?.linkToDeath(observer, 0) 71 val result = Bundle() 72 result.putParcelable( 73 KEY_PREVIEW_SURFACE_PACKAGE, 74 renderer.surfacePackage, 75 ) 76 val messenger = 77 Messenger( 78 Handler( 79 backgroundHandler.looper, 80 observer, 81 ) 82 ) 83 val msg = Message.obtain() 84 msg.replyTo = messenger 85 result.putParcelable(KEY_PREVIEW_CALLBACK, msg) 86 result 87 } catch (e: Exception) { 88 Log.e(TAG, "Unable to generate preview", e) 89 observer?.let { destroyObserver(it) } 90 null 91 } 92 } 93 94 private fun destroyObserver(observer: PreviewLifecycleObserver) { 95 observer.onDestroy()?.let { hostToken -> 96 if (activePreviews[hostToken] === observer) { 97 activePreviews.remove(hostToken) 98 } 99 } 100 } 101 102 private class PreviewLifecycleObserver( 103 private val renderer: KeyguardPreviewRenderer, 104 private val scope: CoroutineScope, 105 private val mainDispatcher: CoroutineDispatcher, 106 private val requestDestruction: (PreviewLifecycleObserver) -> Unit, 107 ) : Handler.Callback, IBinder.DeathRecipient { 108 109 private var isDestroyedOrDestroying = false 110 111 override fun handleMessage(message: Message): Boolean { 112 if (isDestroyedOrDestroying) { 113 return true 114 } 115 116 when (message.what) { 117 KeyguardQuickAffordancePreviewConstants.MESSAGE_ID_SLOT_SELECTED -> { 118 message.data 119 .getString( 120 KeyguardQuickAffordancePreviewConstants.KEY_SLOT_ID, 121 ) 122 ?.let { slotId -> renderer.onSlotSelected(slotId = slotId) } 123 } 124 else -> requestDestruction(this) 125 } 126 127 return true 128 } 129 130 override fun binderDied() { 131 requestDestruction(this) 132 } 133 134 fun onDestroy(): IBinder? { 135 if (isDestroyedOrDestroying) { 136 return null 137 } 138 139 isDestroyedOrDestroying = true 140 val hostToken = renderer.hostToken 141 hostToken?.unlinkToDeath(this, 0) 142 scope.launch(mainDispatcher) { renderer.destroy() } 143 return hostToken 144 } 145 } 146 147 companion object { 148 private const val TAG = "KeyguardRemotePreviewManager" 149 @VisibleForTesting const val KEY_PREVIEW_SURFACE_PACKAGE = "surface_package" 150 @VisibleForTesting const val KEY_PREVIEW_CALLBACK = "callback" 151 } 152 } 153