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.car.carlauncher.datasources
18 
19 import android.content.ComponentName
20 import android.content.Context
21 import android.content.Intent
22 import android.content.pm.PackageManager
23 import android.content.pm.ResolveInfo
24 import android.service.media.MediaBrowserService
25 import com.android.car.media.common.source.MediaSource.isAudioMediaSource
26 import com.android.car.media.common.source.MediaSource.isMediaTemplate
27 import kotlinx.coroutines.CoroutineDispatcher
28 import kotlinx.coroutines.withContext
29 
30 /**
31  * DataSource interface for MediaTemplate apps
32  */
33 interface MediaTemplateAppsDataSource {
34 
35     /**
36      * Get all media services on the device
37      * @param includeCustomMediaPackages
38      */
getAllMediaServicesnull39     suspend fun getAllMediaServices(includeCustomMediaPackages: Boolean): List<ResolveInfo>
40 }
41 
42 /**
43  * Impl of [MediaTemplateAppsDataSource], surfaces all media template apps related queries
44  *
45  * @property packageManager to query MediaServices.
46  * @param appContext application context, not bound to activity's configuration changes.
47  * @property [bgDispatcher] executes all the operations on this background coroutine dispatcher.
48  */
49 class MediaTemplateAppsDataSourceImpl(
50     private val packageManager: PackageManager,
51     private val appContext: Context,
52     private val bgDispatcher: CoroutineDispatcher
53 ) : MediaTemplateAppsDataSource {
54 
55     /**
56      * Gets all media services for MediaTemplateApps.
57      *
58      * @param includeCustomMediaPackages if false, only gets MediaTemplateApps.
59      *                                   if true, in addition to MediaTemplateApps also include
60      *                                   custom media components.
61      */
62     override suspend fun getAllMediaServices(
63         includeCustomMediaPackages: Boolean
64     ): List<ResolveInfo> {
65         val filterFunction = if (includeCustomMediaPackages) {
66             ::isAudioMediaSource
67         } else {
68             ::isMediaTemplate
69         }
70         return withContext(bgDispatcher) {
71             packageManager.queryIntentServices(
72                 Intent(MediaBrowserService.SERVICE_INTERFACE),
73                 PackageManager.GET_RESOLVED_FILTER
74             ).filter {
75                 val componentName = ComponentName(it.serviceInfo.packageName, it.serviceInfo.name)
76                 filterFunction(appContext, componentName)
77             }
78         }
79     }
80 
81     companion object {
82         val TAG: String = MediaTemplateAppsDataSourceImpl::class.java.simpleName
83     }
84 }
85