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.media.MediaProjectionAppSelectorActivity 27 import com.android.systemui.media.MediaProjectionAppSelectorActivity.Companion.EXTRA_HOST_APP_USER_HANDLE 28 import com.android.systemui.media.MediaProjectionPermissionActivity 29 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader 30 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader 31 import com.android.systemui.mediaprojection.appselector.data.AppIconLoader 32 import com.android.systemui.mediaprojection.appselector.data.IconLoaderLibAppIconLoader 33 import com.android.systemui.mediaprojection.appselector.data.RecentTaskLabelLoader 34 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider 35 import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader 36 import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider 37 import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController 38 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider 39 import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule 40 import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile 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 @Retention(AnnotationRetention.RUNTIME) @Scope annotation class MediaProjectionAppSelectorScope 61 62 @Module( 63 subcomponents = [MediaProjectionAppSelectorComponent::class], 64 includes = [MediaProjectionDevicePolicyModule::class] 65 ) 66 interface MediaProjectionModule { 67 @Binds 68 @IntoMap 69 @ClassKey(MediaProjectionAppSelectorActivity::class) 70 fun provideMediaProjectionAppSelectorActivity( 71 activity: MediaProjectionAppSelectorActivity 72 ): Activity 73 74 @Binds 75 @IntoMap 76 @ClassKey(MediaProjectionPermissionActivity::class) 77 fun bindsMediaProjectionPermissionActivity(impl: MediaProjectionPermissionActivity): Activity 78 } 79 80 /** 81 * Scoped values for [MediaProjectionAppSelectorComponent]. We create a scope for the activity so 82 * certain dependencies like [TaskPreviewSizeProvider] could be reused. 83 */ 84 @Module 85 interface MediaProjectionAppSelectorModule { 86 87 @Binds 88 @MediaProjectionAppSelectorScope 89 fun bindRecentTaskThumbnailLoader( 90 impl: ActivityTaskManagerThumbnailLoader 91 ): RecentTaskThumbnailLoader 92 93 @Binds 94 @MediaProjectionAppSelectorScope 95 fun bindRecentTaskLabelLoader(impl: ActivityTaskManagerLabelLoader): RecentTaskLabelLoader 96 97 @Binds 98 @MediaProjectionAppSelectorScope 99 fun bindRecentTaskListProvider(impl: ShellRecentTaskListProvider): RecentTaskListProvider 100 101 @Binds 102 @MediaProjectionAppSelectorScope 103 fun bindAppIconLoader(impl: IconLoaderLibAppIconLoader): AppIconLoader 104 105 @Binds 106 @IntoSet 107 fun taskPreviewSizeProviderAsLifecycleObserver( 108 impl: TaskPreviewSizeProvider 109 ): DefaultLifecycleObserver 110 111 companion object { 112 @Provides 113 @MediaProjectionAppSelector 114 @MediaProjectionAppSelectorScope 115 fun provideAppSelectorComponentName(context: Context): ComponentName = 116 ComponentName(context, MediaProjectionAppSelectorActivity::class.java) 117 118 @Provides 119 @MediaProjectionAppSelector 120 @MediaProjectionAppSelectorScope 121 fun provideCallerPackageName(activity: MediaProjectionAppSelectorActivity): String? = 122 activity.callingPackage 123 124 @Provides 125 @MediaProjectionAppSelector 126 @MediaProjectionAppSelectorScope 127 fun bindConfigurationController( 128 activity: MediaProjectionAppSelectorActivity 129 ): ConfigurationController = ConfigurationControllerImpl(activity) 130 131 @Provides 132 @HostUserHandle 133 @MediaProjectionAppSelectorScope 134 fun hostUserHandle(activity: MediaProjectionAppSelectorActivity): UserHandle { 135 val extras = 136 activity.intent.extras 137 ?: error("MediaProjectionAppSelectorActivity should be launched with extras") 138 return extras.getParcelable(EXTRA_HOST_APP_USER_HANDLE) 139 ?: error( 140 "MediaProjectionAppSelectorActivity should be provided with " + 141 "$EXTRA_HOST_APP_USER_HANDLE extra" 142 ) 143 } 144 145 @Provides fun bindIconFactory(context: Context): IconFactory = IconFactory.obtain(context) 146 147 @Provides 148 @MediaProjectionAppSelector 149 @MediaProjectionAppSelectorScope 150 fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope = 151 CoroutineScope(applicationScope.coroutineContext + SupervisorJob()) 152 } 153 } 154 155 @Subcomponent(modules = [MediaProjectionAppSelectorModule::class]) 156 @MediaProjectionAppSelectorScope 157 interface MediaProjectionAppSelectorComponent { 158 159 /** Generates [MediaProjectionAppSelectorComponent]. */ 160 @Subcomponent.Factory 161 interface Factory { 162 /** Create a factory to inject the activity into the graph */ 163 fun create( 164 @BindsInstance activity: MediaProjectionAppSelectorActivity, 165 @BindsInstance view: MediaProjectionAppSelectorView, 166 @BindsInstance resultHandler: MediaProjectionAppSelectorResultHandler, 167 ): MediaProjectionAppSelectorComponent 168 } 169 170 val controller: MediaProjectionAppSelectorController 171 val recentsViewController: MediaProjectionRecentsViewController 172 val emptyStateProvider: MediaProjectionBlockerEmptyStateProvider 173 @get:HostUserHandle val hostUserHandle: UserHandle 174 @get:PersonalProfile val personalProfileUserHandle: UserHandle 175 176 @MediaProjectionAppSelector val configurationController: ConfigurationController 177 val lifecycleObservers: Set<DefaultLifecycleObserver> 178 } 179