1 /* 2 * 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 package com.android.systemui.util 18 19 import android.app.IActivityTaskManager 20 import android.app.WaitResult 21 import android.content.Context 22 import android.content.Intent 23 import android.os.Bundle 24 import android.os.UserHandle 25 import com.android.systemui.dagger.qualifiers.Main 26 import com.android.systemui.dagger.qualifiers.UiBackground 27 import java.util.concurrent.Executor 28 import javax.inject.Inject 29 30 /** 31 * Helper class that allows to launch an activity and asynchronously wait 32 * for it to be launched. This class uses application context, so the intent 33 * will be launched with FLAG_ACTIVITY_NEW_TASK. 34 */ 35 class AsyncActivityLauncher @Inject constructor( 36 private val context: Context, 37 private val activityTaskManager: IActivityTaskManager, 38 @UiBackground private val backgroundExecutor: Executor, 39 @Main private val mainExecutor: Executor 40 ) { 41 42 private var pendingCallback: ((WaitResult) -> Unit)? = null 43 44 /** 45 * Starts activity and notifies about the result using the provided [callback]. 46 * If there is already pending activity launch the call will be ignored. 47 * 48 * @return true if launch has started, false otherwise 49 */ startActivityAsUsernull50 fun startActivityAsUser(intent: Intent, userHandle: UserHandle, 51 activityOptions: Bundle? = null, 52 callback: (WaitResult) -> Unit): Boolean { 53 if (pendingCallback != null) return false 54 55 pendingCallback = callback 56 57 intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK 58 59 backgroundExecutor.execute { 60 val waitResult = activityTaskManager.startActivityAndWait( 61 /* caller = */ null, 62 /* callingPackage = */ context.packageName, 63 /* callingFeatureId = */ context.attributionTag, 64 /* intent = */ intent, 65 /* resolvedType = */ null, 66 /* resultTo = */ null, 67 /* resultWho = */ null, 68 /* requestCode = */ 0, 69 /* flags = */ 0, 70 /* profilerInfo = */ null, 71 /* options = */ activityOptions, 72 /* userId = */ userHandle.identifier 73 ) 74 mainExecutor.execute { 75 pendingCallback?.invoke(waitResult) 76 } 77 } 78 79 return true 80 } 81 82 /** 83 * Cancels pending activity launches. It guarantees that the callback won't be fired 84 * but the activity will be launched anyway. 85 */ destroynull86 fun destroy() { 87 pendingCallback = null 88 } 89 } 90