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.wm.shell.dagger 18 19 import android.os.Handler 20 import com.android.wm.shell.common.ShellExecutor 21 import com.android.wm.shell.shared.annotations.ShellBackgroundThread 22 import com.android.wm.shell.shared.annotations.ShellMainThread 23 import dagger.Module 24 import dagger.Provides 25 import kotlin.coroutines.CoroutineContext 26 import kotlinx.coroutines.CoroutineDispatcher 27 import kotlinx.coroutines.CoroutineScope 28 import kotlinx.coroutines.MainCoroutineDispatcher 29 import kotlinx.coroutines.SupervisorJob 30 import kotlinx.coroutines.android.asCoroutineDispatcher 31 import kotlinx.coroutines.asCoroutineDispatcher 32 33 /** 34 * Providers for various WmShell-specific coroutines-related constructs. 35 * 36 * Providers of [MainCoroutineDispatcher] intentionally creates the dispatcher with a [Handler] 37 * backing it instead of a [ShellExecutor] because [ShellExecutor.asCoroutineDispatcher] will 38 * create a [CoroutineDispatcher] whose [CoroutineDispatcher.isDispatchNeeded] is effectively never 39 * dispatching. This is because even if dispatched, the backing [ShellExecutor.execute] always runs 40 * the [Runnable] immediately if called from the same thread, whereas 41 * [Handler.asCoroutineDispatcher] will create a [MainCoroutineDispatcher] that correctly 42 * dispatches (queues) when [CoroutineDispatcher.isDispatchNeeded] is true using [Handler.post]. 43 * For callers that do need a non-dispatching version, [MainCoroutineDispatcher.immediate] is 44 * available. 45 */ 46 @Module 47 class WMShellCoroutinesModule { 48 @Provides 49 @ShellMainThread provideMainDispatchernull50 fun provideMainDispatcher( 51 @ShellMainThread mainHandler: Handler 52 ): MainCoroutineDispatcher = mainHandler.asCoroutineDispatcher() 53 54 @Provides 55 @ShellBackgroundThread 56 fun provideBackgroundDispatcher( 57 @ShellBackgroundThread backgroundHandler: Handler 58 ): MainCoroutineDispatcher = backgroundHandler.asCoroutineDispatcher() 59 60 @Provides 61 @WMSingleton 62 @ShellMainThread 63 fun provideApplicationScope( 64 @ShellMainThread applicationDispatcher: MainCoroutineDispatcher, 65 ): CoroutineScope = CoroutineScope(applicationDispatcher) 66 67 @Provides 68 @WMSingleton 69 @ShellBackgroundThread 70 fun provideBackgroundCoroutineScope( 71 @ShellBackgroundThread backgroundDispatcher: MainCoroutineDispatcher, 72 ): CoroutineScope = CoroutineScope(backgroundDispatcher) 73 74 @Provides 75 @WMSingleton 76 @ShellBackgroundThread 77 fun provideBackgroundCoroutineContext( 78 @ShellBackgroundThread backgroundDispatcher: MainCoroutineDispatcher 79 ): CoroutineContext = backgroundDispatcher + SupervisorJob() 80 } 81