1 package com.android.systemui.broadcast 2 3 import android.annotation.AnyThread 4 import android.content.Context 5 import android.content.Intent 6 import android.os.Bundle 7 import android.os.UserHandle 8 import com.android.systemui.dagger.SysUISingleton 9 import com.android.systemui.dagger.qualifiers.Background 10 import com.android.systemui.util.wakelock.WakeLock 11 import java.util.concurrent.Executor 12 import javax.inject.Inject 13 14 /** 15 * SystemUI master Broadcast sender 16 * 17 * This class dispatches broadcasts on background thread to avoid synchronous call to binder. Use 18 * this class instead of calling [Context.sendBroadcast] directly. 19 */ 20 @SysUISingleton 21 class BroadcastSender @Inject constructor( 22 private val context: Context, 23 private val wakeLockBuilder: WakeLock.Builder, 24 @Background private val bgExecutor: Executor 25 ) { 26 27 /** 28 * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking 29 * synchronous binder call. 30 */ 31 @AnyThread sendBroadcastnull32 fun sendBroadcast(intent: Intent) { 33 sendInBackground("$intent") { 34 context.sendBroadcast(intent) 35 } 36 } 37 38 /** 39 * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking 40 * synchronous binder call. 41 */ 42 @AnyThread sendBroadcastnull43 fun sendBroadcast(intent: Intent, receiverPermission: String?) { 44 sendInBackground("$intent") { 45 context.sendBroadcast(intent, receiverPermission) 46 } 47 } 48 49 /** 50 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 51 * synchronous binder call. 52 */ 53 @AnyThread sendBroadcastAsUsernull54 fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) { 55 sendInBackground("$intent") { 56 context.sendBroadcastAsUser(intent, userHandle) 57 } 58 } 59 60 /** 61 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 62 * synchronous binder call. 63 */ 64 @AnyThread sendBroadcastAsUsernull65 fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) { 66 sendInBackground("$intent") { 67 context.sendBroadcastAsUser(intent, userHandle, receiverPermission) 68 } 69 } 70 71 /** 72 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 73 * synchronous binder call. 74 */ 75 @AnyThread sendBroadcastAsUsernull76 fun sendBroadcastAsUser( 77 intent: Intent, 78 userHandle: UserHandle, 79 receiverPermission: String?, 80 options: Bundle? 81 ) { 82 sendInBackground("$intent") { 83 context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options) 84 } 85 } 86 87 /** 88 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 89 * synchronous binder call. 90 */ 91 @AnyThread sendBroadcastAsUsernull92 fun sendBroadcastAsUser( 93 intent: Intent, 94 userHandle: UserHandle, 95 receiverPermission: String?, 96 appOp: Int 97 ) { 98 sendInBackground("$intent") { 99 context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp) 100 } 101 } 102 103 /** 104 * Sends [Intent.ACTION_CLOSE_SYSTEM_DIALOGS] broadcast to the system. 105 */ 106 @AnyThread closeSystemDialogsnull107 fun closeSystemDialogs() { 108 sendInBackground("closeSystemDialogs") { 109 context.closeSystemDialogs() 110 } 111 } 112 113 /** 114 * Dispatches parameter on background executor while holding a wakelock. 115 */ sendInBackgroundnull116 private fun sendInBackground(reason: String, callable: () -> Unit) { 117 val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG) 118 .setMaxTimeout(5000) 119 .build() 120 broadcastWakelock.acquire(reason) 121 bgExecutor.execute { 122 try { 123 callable.invoke() 124 } finally { 125 broadcastWakelock.release(reason) 126 } 127 } 128 } 129 130 companion object { 131 private const val WAKE_LOCK_TAG = "SysUI:BroadcastSender" 132 } 133 }