1 /*
<lambda>null2 * Copyright 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.photopicker.extensions
18
19 import android.content.Intent
20 import android.provider.MediaStore
21 import com.android.photopicker.core.configuration.IllegalIntentExtraException
22
23 /**
24 * Check the various possible actions the intent could be running under and extract a valid value
25 * from EXTRA_PICK_IMAGES_MAX
26 *
27 * @param default The default value to use if a suitable one cannot be found.
28 * @return a valid selection limit set on the [Intent], or the default value if the provided value
29 * is invalid, or not set.
30 */
31 fun Intent.getPhotopickerSelectionLimitOrDefault(default: Int): Int {
32
33 val limit =
34 if (
35 getAction() == MediaStore.ACTION_PICK_IMAGES &&
36 getExtras()?.containsKey(MediaStore.EXTRA_PICK_IMAGES_MAX) ?: false
37 ) {
38 // ACTION_PICK_IMAGES supports EXTRA_PICK_IMAGES_MAX,
39 // so return the value from the intent
40 getIntExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, -1)
41 } else if (
42 getAction() == Intent.ACTION_GET_CONTENT &&
43 extras?.containsKey(MediaStore.EXTRA_PICK_IMAGES_MAX) ?: false
44 ) {
45 // GET_CONTENT does not support EXTRA_PICK_IMAGES_MAX
46 throw IllegalIntentExtraException(
47 "EXTRA_PICK_IMAGES_MAX is not allowed for ACTION_GET_CONTENT, " +
48 "use ACTION_PICK_IMAGES instead."
49 )
50 } else {
51 // No EXTRA_PICK_IMAGES_MAX was set, return the provided default
52 default
53 }
54
55 // Ensure the limit extracted from above is in the allowed range
56 if (limit !in 1..MediaStore.getPickImagesMaxLimit()) {
57 throw IllegalIntentExtraException(
58 "EXTRA_PICK_IMAGES_MAX not in the allowed range. Must be between 1 " +
59 "and ${MediaStore.getPickImagesMaxLimit()}"
60 )
61 }
62
63 return limit
64 }
65
66 /**
67 * @return An [ArrayList] of MIME type filters derived from the intent. If no MIME type filters
68 * should be applied, return null.
69 * @throws [IllegalIntentExtraException] if the input MIME types filters cannot be applied.
70 */
Intentnull71 fun Intent.getPhotopickerMimeTypes(): ArrayList<String>? {
72 val mimeTypes: Array<String>? = getStringArrayExtra(Intent.EXTRA_MIME_TYPES)
73 if (mimeTypes != null) {
74 if (mimeTypes.all { mimeType -> isMediaMimeType(mimeType) }) {
75 return mimeTypes.toCollection(ArrayList())
76 } else {
77 // Picker can be opened from Documents UI by the user. In this case, the intent action
78 // will be Intent.ACTION_GET_CONTENT and the mime types may contain non-media types.
79 // Don't apply any MIME type filters in this case. Otherwise, throw an exception.
80 if (!action.equals(Intent.ACTION_GET_CONTENT)) {
81 throw IllegalIntentExtraException(
82 "Only media MIME types can be accepted. Input MIME types: $mimeTypes"
83 )
84 }
85 }
86 } else {
87 // Ignore the set type if it is not media type and don't apply any MIME type filters.
88 if (type != null && isMediaMimeType(type!!)) return arrayListOf(type!!)
89 }
90 return null
91 }
92
93 /**
94 * Determines if Photopicker is capable of handling the [Intent.EXTRA_MIME_TYPES] provided to the
95 * activity in this Photopicker session launched with [android.intent.ACTION_GET_CONTENT].
96 *
97 * @return true if the list of mimetypes can be handled by Photopicker.
98 */
canHandleGetContentIntentMimeTypesnull99 fun Intent.canHandleGetContentIntentMimeTypes(): Boolean {
100 if (!hasExtra(Intent.EXTRA_MIME_TYPES)) {
101 // If the incoming type is */* then Photopicker can't handle this mimetype
102 return isMediaMimeType(getType())
103 }
104
105 val mimeTypes = getStringArrayExtra(Intent.EXTRA_MIME_TYPES)
106 mimeTypes?.let {
107
108 // If the list of MimeTypes is empty, nothing was explicitly set, so assume that
109 // non-media files should be displayed.
110 if (mimeTypes.size == 0) return false
111
112 // Ensure all mimetypes in the incoming filter list are supported
113 for (mimeType in mimeTypes) {
114 if (!isMediaMimeType(mimeType)) {
115 return false
116 }
117 }
118 }
119 // Should not be null at this point (the intent contains the extra key),
120 // but better safe than sorry.
121 ?: return false
122
123 return true
124 }
125
126 /**
127 * Determines if the mimeType is a media mimetype that Photopicker can support.
128 *
129 * @return Whether the mimetype is supported by Photopicker.
130 */
isMediaMimeTypenull131 private fun isMediaMimeType(mimeType: String?): Boolean {
132 return mimeType?.let { it.startsWith("image/") || it.startsWith("video/") } ?: false
133 }
134