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.mediaprojection.appselector
18 
19 import android.app.Activity
20 import android.content.ComponentName
21 import android.content.Context
22 import android.os.UserHandle
23 import androidx.lifecycle.DefaultLifecycleObserver
24 import com.android.launcher3.icons.IconFactory
25 import com.android.systemui.dagger.qualifiers.Application
26 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader
27 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
28 import com.android.systemui.mediaprojection.appselector.data.BasicAppIconLoader
29 import com.android.systemui.mediaprojection.appselector.data.BasicPackageManagerAppIconLoader
30 import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader
31 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
32 import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
33 import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider
34 import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController
35 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider
36 import com.android.systemui.mediaprojection.appselector.view.WindowMetricsProvider
37 import com.android.systemui.mediaprojection.appselector.view.WindowMetricsProviderImpl
38 import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule
39 import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile
40 import com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity
41 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
42 import com.android.systemui.statusbar.policy.ConfigurationController
43 import dagger.Binds
44 import dagger.BindsInstance
45 import dagger.Module
46 import dagger.Provides
47 import dagger.Subcomponent
48 import dagger.multibindings.ClassKey
49 import dagger.multibindings.IntoMap
50 import dagger.multibindings.IntoSet
51 import javax.inject.Qualifier
52 import javax.inject.Scope
53 import kotlinx.coroutines.CoroutineScope
54 import kotlinx.coroutines.SupervisorJob
55 
56 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class MediaProjectionAppSelector
57 
58 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class HostUserHandle
59 
60 @Qualifier @Retention(AnnotationRetention.BINARY) annotation class HostUid
61 
62 @Retention(AnnotationRetention.RUNTIME) @Scope annotation class MediaProjectionAppSelectorScope
63 
64 @Module(
65     subcomponents = [MediaProjectionAppSelectorComponent::class],
66     includes = [MediaProjectionDevicePolicyModule::class]
67 )
68 interface MediaProjectionActivitiesModule {
69     @Binds
70     @IntoMap
71     @ClassKey(MediaProjectionAppSelectorActivity::class)
provideMediaProjectionAppSelectorActivitynull72     fun provideMediaProjectionAppSelectorActivity(
73         activity: MediaProjectionAppSelectorActivity
74     ): Activity
75 
76     @Binds
77     @IntoMap
78     @ClassKey(MediaProjectionPermissionActivity::class)
79     fun bindsMediaProjectionPermissionActivity(impl: MediaProjectionPermissionActivity): Activity
80 }
81 
82 /**
83  * Scoped values for [MediaProjectionAppSelectorComponent]. We create a scope for the activity so
84  * certain dependencies like [TaskPreviewSizeProvider] could be reused.
85  */
86 @Module
87 interface MediaProjectionAppSelectorModule {
88 
89     @Binds
90     @MediaProjectionAppSelectorScope
91     fun bindRecentTaskThumbnailLoader(
92         impl: ActivityTaskManagerThumbnailLoader
93     ): RecentTaskThumbnailLoader
94 
95     @Binds
96     @MediaProjectionAppSelectorScope
97     fun bindRecentTaskLabelLoader(impl: ActivityTaskManagerLabelLoader): RecentTaskLabelLoader
98 
99     @Binds
100     @MediaProjectionAppSelectorScope
101     fun bindRecentTaskListProvider(impl: ShellRecentTaskListProvider): RecentTaskListProvider
102 
103     @Binds
104     @MediaProjectionAppSelectorScope
105     fun bindAppIconLoader(impl: BasicPackageManagerAppIconLoader): BasicAppIconLoader
106 
107     @Binds
108     @IntoSet
109     fun taskPreviewSizeProviderAsLifecycleObserver(
110         impl: TaskPreviewSizeProvider
111     ): DefaultLifecycleObserver
112 
113     @Binds fun windowMetricsProvider(impl: WindowMetricsProviderImpl): WindowMetricsProvider
114 
115     companion object {
116         @Provides
117         @MediaProjectionAppSelector
118         @MediaProjectionAppSelectorScope
119         fun provideAppSelectorComponentName(context: Context): ComponentName =
120             ComponentName(context, MediaProjectionAppSelectorActivity::class.java)
121 
122         @Provides
123         @MediaProjectionAppSelector
124         @MediaProjectionAppSelectorScope
125         fun bindConfigurationController(context: Context): ConfigurationController =
126             ConfigurationControllerImpl(context)
127 
128         @Provides fun bindIconFactory(context: Context): IconFactory = IconFactory.obtain(context)
129 
130         @Provides
131         @MediaProjectionAppSelector
132         @MediaProjectionAppSelectorScope
133         fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope =
134             CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
135     }
136 }
137 
138 @Subcomponent(modules = [MediaProjectionAppSelectorModule::class])
139 @MediaProjectionAppSelectorScope
140 interface MediaProjectionAppSelectorComponent {
141 
142     /** Generates [MediaProjectionAppSelectorComponent]. */
143     @Subcomponent.Factory
144     interface Factory {
145         /** Create a factory to inject the activity into the graph */
createnull146         fun create(
147             @BindsInstance @HostUserHandle hostUserHandle: UserHandle,
148             @BindsInstance @HostUid hostUid: Int,
149             @BindsInstance @MediaProjectionAppSelector callingPackage: String?,
150             @BindsInstance view: MediaProjectionAppSelectorView,
151             @BindsInstance resultHandler: MediaProjectionAppSelectorResultHandler,
152             // Whether the app selector is starting for the first time. False when it is re-starting
153             // due to a config change.
154             @BindsInstance @MediaProjectionAppSelector isFirstStart: Boolean,
155         ): MediaProjectionAppSelectorComponent
156     }
157 
158     val controller: MediaProjectionAppSelectorController
159     val recentsViewController: MediaProjectionRecentsViewController
160     val emptyStateProvider: MediaProjectionBlockerEmptyStateProvider
161     @get:HostUserHandle val hostUserHandle: UserHandle
162     @get:PersonalProfile val personalProfileUserHandle: UserHandle
163 
164     @MediaProjectionAppSelector val configurationController: ConfigurationController
165     val lifecycleObservers: Set<DefaultLifecycleObserver>
166 }
167