• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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.intentresolver.inject
18 
19 import android.content.Intent
20 import android.net.Uri
21 import android.os.Bundle
22 import android.service.chooser.ChooserAction
23 import androidx.lifecycle.SavedStateHandle
24 import com.android.intentresolver.Flags.saveShareouselState
25 import com.android.intentresolver.data.model.ChooserRequest
26 import com.android.intentresolver.data.repository.ActivityModelRepository
27 import com.android.intentresolver.ui.viewmodel.CHOOSER_REQUEST_KEY
28 import com.android.intentresolver.ui.viewmodel.readChooserRequest
29 import com.android.intentresolver.util.ownedByCurrentUser
30 import com.android.intentresolver.validation.Valid
31 import com.android.intentresolver.validation.ValidationResult
32 import dagger.Module
33 import dagger.Provides
34 import dagger.hilt.InstallIn
35 import dagger.hilt.android.components.ViewModelComponent
36 import dagger.hilt.android.scopes.ViewModelScoped
37 import javax.inject.Qualifier
38 
39 @Module
40 @InstallIn(ViewModelComponent::class)
41 object ActivityModelModule {
42     @Provides
43     @ChooserIntent
44     fun chooserIntent(activityModelRepo: ActivityModelRepository): Intent =
45         activityModelRepo.value.intent
46 
47     @Provides
48     @ViewModelScoped
49     fun provideInitialRequest(
50         activityModelRepo: ActivityModelRepository,
51         savedStateHandle: SavedStateHandle,
52     ): ValidationResult<ChooserRequest> {
53         val activityModel = activityModelRepo.value
54         val extras = restoreChooserRequestExtras(activityModel.intent.extras, savedStateHandle)
55         return readChooserRequest(activityModel, extras)
56     }
57 
58     @Provides
59     fun provideChooserRequest(initialRequest: ValidationResult<ChooserRequest>): ChooserRequest =
60         requireNotNull((initialRequest as? Valid)?.value) {
61             "initialRequest is Invalid, no chooser request available"
62         }
63 
64     @Provides
65     @TargetIntent
66     fun targetIntent(chooserReq: ValidationResult<ChooserRequest>): Intent =
67         requireNotNull((chooserReq as? Valid)?.value?.targetIntent) { "no target intent available" }
68 
69     @Provides
70     fun customActions(chooserReq: ValidationResult<ChooserRequest>): List<ChooserAction> =
71         requireNotNull((chooserReq as? Valid)?.value?.chooserActions) {
72             "no chooser actions available"
73         }
74 
75     @Provides
76     @ViewModelScoped
77     @ContentUris
78     fun selectedUris(chooserRequest: ValidationResult<ChooserRequest>): List<Uri> =
79         requireNotNull((chooserRequest as? Valid)?.value?.targetIntent?.contentUris?.toList()) {
80             "no selected uris available"
81         }
82 
83     @Provides
84     @FocusedItemIndex
85     fun focusedItemIndex(chooserReq: ValidationResult<ChooserRequest>): Int =
86         requireNotNull((chooserReq as? Valid)?.value?.focusedItemPosition) {
87             "no focused item position available"
88         }
89 
90     @Provides
91     @AdditionalContent
92     fun additionalContentUri(chooserReq: ValidationResult<ChooserRequest>): Uri =
93         requireNotNull((chooserReq as? Valid)?.value?.additionalContentUri) {
94             "no additional content uri available"
95         }
96 }
97 
98 @Qualifier
99 @MustBeDocumented
100 @Retention(AnnotationRetention.RUNTIME)
101 annotation class FocusedItemIndex
102 
103 @Qualifier
104 @MustBeDocumented
105 @Retention(AnnotationRetention.RUNTIME)
106 annotation class AdditionalContent
107 
108 @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class ChooserIntent
109 
110 @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class ContentUris
111 
112 @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class TargetIntent
113 
114 private val Intent.contentUris: Sequence<Uri>
<lambda>null115     get() = sequence {
116         if (Intent.ACTION_SEND == action) {
117             getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
118                 ?.takeIf { it.ownedByCurrentUser }
119                 ?.let { yield(it) }
120         } else {
121             getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.forEach { uri ->
122                 if (uri.ownedByCurrentUser) {
123                     yield(uri)
124                 }
125             }
126         }
127     }
128 
restoreChooserRequestExtrasnull129 private fun restoreChooserRequestExtras(
130     initialExtras: Bundle?,
131     savedStateHandle: SavedStateHandle,
132 ): Bundle =
133     if (saveShareouselState()) {
134         savedStateHandle.get<Bundle>(CHOOSER_REQUEST_KEY)?.let { savedSateBundle ->
135             Bundle().apply {
136                 initialExtras?.let { putAll(it) }
137                 putAll(savedSateBundle)
138             }
139         } ?: initialExtras
140     } else {
141         initialExtras
142     } ?: Bundle()
143