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