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 private val WAKE_LOCK_TAG = "SysUI:BroadcastSender" 28 private val WAKE_LOCK_SEND_REASON = "sendInBackground" 29 30 /** 31 * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking 32 * synchronous binder call. 33 */ 34 @AnyThread sendBroadcastnull35 fun sendBroadcast(intent: Intent) { 36 sendInBackground { 37 context.sendBroadcast(intent) 38 } 39 } 40 41 /** 42 * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking 43 * synchronous binder call. 44 */ 45 @AnyThread sendBroadcastnull46 fun sendBroadcast(intent: Intent, receiverPermission: String?) { 47 sendInBackground { 48 context.sendBroadcast(intent, receiverPermission) 49 } 50 } 51 52 /** 53 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 54 * synchronous binder call. 55 */ 56 @AnyThread sendBroadcastAsUsernull57 fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) { 58 sendInBackground { 59 context.sendBroadcastAsUser(intent, userHandle) 60 } 61 } 62 63 /** 64 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 65 * synchronous binder call. 66 */ 67 @AnyThread sendBroadcastAsUsernull68 fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) { 69 sendInBackground { 70 context.sendBroadcastAsUser(intent, userHandle, receiverPermission) 71 } 72 } 73 74 /** 75 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 76 * synchronous binder call. 77 */ 78 @AnyThread sendBroadcastAsUsernull79 fun sendBroadcastAsUser( 80 intent: Intent, 81 userHandle: UserHandle, 82 receiverPermission: String?, 83 options: Bundle? 84 ) { 85 sendInBackground { 86 context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options) 87 } 88 } 89 90 /** 91 * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking 92 * synchronous binder call. 93 */ 94 @AnyThread sendBroadcastAsUsernull95 fun sendBroadcastAsUser( 96 intent: Intent, 97 userHandle: UserHandle, 98 receiverPermission: String?, 99 appOp: Int 100 ) { 101 sendInBackground { 102 context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp) 103 } 104 } 105 106 /** 107 * Sends [Intent.ACTION_CLOSE_SYSTEM_DIALOGS] broadcast to the system. 108 */ 109 @AnyThread closeSystemDialogsnull110 fun closeSystemDialogs() { 111 sendInBackground { 112 context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) 113 } 114 } 115 116 /** 117 * Dispatches parameter on background executor while holding a wakelock. 118 */ sendInBackgroundnull119 private fun sendInBackground(callable: () -> Unit) { 120 val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG) 121 .setMaxTimeout(5000) 122 .build() 123 broadcastWakelock.acquire(WAKE_LOCK_SEND_REASON) 124 bgExecutor.execute { 125 try { 126 callable.invoke() 127 } finally { 128 broadcastWakelock.release(WAKE_LOCK_SEND_REASON) 129 } 130 } 131 } 132 }