1 /*
<lambda>null2  * Copyright (C) 2023 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  */
18 
19 /**
20  * Copyright (C) 2022 The Android Open Source Project
21  *
22  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23  * in compliance with the License. You may obtain a copy of the License at
24  *
25  * ```
26  *      http://www.apache.org/licenses/LICENSE-2.0
27  * ```
28  *
29  * Unless required by applicable law or agreed to in writing, software distributed under the License
30  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
31  * or implied. See the License for the specific language governing permissions and limitations under
32  * the License.
33  */
34 package com.android.healthconnect.controller.shared.app
35 
36 import android.content.Context
37 import android.graphics.Bitmap
38 import android.graphics.drawable.BitmapDrawable
39 import android.graphics.drawable.Drawable
40 import android.health.connect.ApplicationInfoResponse
41 import android.health.connect.HealthConnectManager
42 import android.health.connect.datatypes.AppInfo
43 import android.util.Log
44 import androidx.core.os.asOutcomeReceiver
45 import com.android.healthconnect.controller.service.IoDispatcher
46 import dagger.hilt.android.qualifiers.ApplicationContext
47 import javax.inject.Inject
48 import javax.inject.Singleton
49 import kotlinx.coroutines.CoroutineDispatcher
50 import kotlinx.coroutines.suspendCancellableCoroutine
51 import kotlinx.coroutines.withContext
52 
53 @Singleton
54 class GetContributorAppInfoUseCase
55 @Inject
56 constructor(
57     private val healthConnectManager: HealthConnectManager,
58     @ApplicationContext private val context: Context,
59     @IoDispatcher private val dispatcher: CoroutineDispatcher
60 ) : IGetContributorAppInfoUseCase {
61     companion object {
62         private const val TAG = "GetContributorAppInfo"
63     }
64 
65     override suspend fun invoke(): Map<String, AppMetadata> =
66         withContext(dispatcher) {
67             try {
68                 val appInfoList =
69                     suspendCancellableCoroutine<ApplicationInfoResponse> { continuation ->
70                             healthConnectManager.getContributorApplicationsInfo(
71                                 Runnable::run, continuation.asOutcomeReceiver())
72                         }
73                         .applicationInfoList
74                 appInfoList.associate { it.packageName to toAppMetadata(it) }
75             } catch (e: Exception) {
76                 Log.e(TAG, "GetContributorApplicationsInfoUseCase", e)
77                 emptyMap()
78             }
79         }
80 
81     private fun toAppMetadata(appInfo: AppInfo): AppMetadata {
82         return AppMetadata(
83             packageName = appInfo.packageName,
84             appName =
85                 appInfo.name
86                     ?: appInfo.packageName, // default to package name if appInfo name is null
87             icon = getIcon(appInfo.icon))
88     }
89 
90     private fun getIcon(bitmap: Bitmap?): Drawable? {
91         return bitmap?.let { BitmapDrawable(context.resources, it) }
92     }
93 }
94 
95 interface IGetContributorAppInfoUseCase {
invokenull96     suspend operator fun invoke(): Map<String, AppMetadata>
97 }
98