1 /**
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * ```
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  * ```
10  *
11  * Unless required by applicable law or agreed to in writing, software distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.healthconnect.testapps.toolbox.utils
17 
18 import androidx.concurrent.futures.CallbackToFutureAdapter
19 import androidx.concurrent.futures.DirectExecutor
20 import com.google.common.util.concurrent.ListenableFuture
21 import kotlinx.coroutines.CancellationException
22 import kotlinx.coroutines.CoroutineScope
23 import kotlinx.coroutines.Dispatchers
24 import kotlinx.coroutines.cancel
25 import kotlinx.coroutines.launch
26 import kotlin.coroutines.CoroutineContext
27 
28 /**
29  * Launches a new coroutine and wraps it in [ListenableFuture].
30  *
31  * Temporary until the stable version 1.2.0 of androidx.concurrent:concurrent-futures-ktx,
32  * where SuspendToFutureAdapter will be available.
33  */
34 internal fun <T> launchFuture(
35     context: CoroutineContext = Dispatchers.Main,
36     block: suspend CoroutineScope.() -> T,
37 ): ListenableFuture<T> =
38     CallbackToFutureAdapter.getFuture { completer ->
39         val scope = CoroutineScope(context)
40 
41         scope.launch {
42             try {
43                 completer.set(block())
44             } catch (e: CancellationException) {
45                 completer.setCancelled()
46             } catch (e: Throwable) {
47                 completer.setException(e)
48             }
49         }
50 
51         completer.addCancellationListener(Runnable(scope::cancel), DirectExecutor.INSTANCE)
52     }
53