• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.contentpreview;
18 
19 import static com.android.intentresolver.contentpreview.ContentPreviewType.CONTENT_PREVIEW_IMAGE;
20 
21 import android.content.res.Resources;
22 import android.util.Log;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 
27 import androidx.annotation.Nullable;
28 
29 import com.android.intentresolver.R;
30 import com.android.intentresolver.widget.ActionRow;
31 import com.android.intentresolver.widget.ImagePreviewView.TransitionElementStatusCallback;
32 import com.android.intentresolver.widget.ScrollableImagePreviewView;
33 
34 import kotlinx.coroutines.CoroutineScope;
35 import kotlinx.coroutines.flow.Flow;
36 
37 import java.util.List;
38 import java.util.Objects;
39 
40 class UnifiedContentPreviewUi extends ContentPreviewUi {
41     private final boolean mShowEditAction;
42     @Nullable
43     private final String mIntentMimeType;
44     private final ChooserContentPreviewUi.ActionFactory mActionFactory;
45     private final ImageLoader mImageLoader;
46     private final MimeTypeClassifier mTypeClassifier;
47     private final TransitionElementStatusCallback mTransitionElementStatusCallback;
48     private final HeadlineGenerator mHeadlineGenerator;
49     @Nullable
50     private final CharSequence mMetadata;
51     private final Flow<FileInfo> mFileInfoFlow;
52     private final int mItemCount;
53     @Nullable
54     private List<FileInfo> mFiles;
55     @Nullable
56     private ViewGroup mContentPreviewView;
57     private View mHeadlineView;
58 
UnifiedContentPreviewUi( CoroutineScope scope, boolean isSingleImage, @Nullable String intentMimeType, ChooserContentPreviewUi.ActionFactory actionFactory, ImageLoader imageLoader, MimeTypeClassifier typeClassifier, TransitionElementStatusCallback transitionElementStatusCallback, Flow<FileInfo> fileInfoFlow, int itemCount, HeadlineGenerator headlineGenerator, @Nullable CharSequence metadata)59     UnifiedContentPreviewUi(
60             CoroutineScope scope,
61             boolean isSingleImage,
62             @Nullable String intentMimeType,
63             ChooserContentPreviewUi.ActionFactory actionFactory,
64             ImageLoader imageLoader,
65             MimeTypeClassifier typeClassifier,
66             TransitionElementStatusCallback transitionElementStatusCallback,
67             Flow<FileInfo> fileInfoFlow,
68             int itemCount,
69             HeadlineGenerator headlineGenerator,
70             @Nullable CharSequence metadata) {
71         mShowEditAction = isSingleImage;
72         mIntentMimeType = intentMimeType;
73         mActionFactory = actionFactory;
74         mImageLoader = imageLoader;
75         mTypeClassifier = typeClassifier;
76         mTransitionElementStatusCallback = transitionElementStatusCallback;
77         mFileInfoFlow = fileInfoFlow;
78         mItemCount = itemCount;
79         mHeadlineGenerator = headlineGenerator;
80         mMetadata = metadata;
81 
82         JavaFlowHelper.collectToList(scope, fileInfoFlow, this::setFiles);
83     }
84 
85     @Override
getType()86     public int getType() {
87         return CONTENT_PREVIEW_IMAGE;
88     }
89 
90     @Override
display( Resources resources, LayoutInflater layoutInflater, ViewGroup parent, View headlineViewParent)91     public ViewGroup display(
92             Resources resources,
93             LayoutInflater layoutInflater,
94             ViewGroup parent,
95             View headlineViewParent) {
96         return displayInternal(layoutInflater, parent, headlineViewParent);
97     }
98 
setFiles(List<FileInfo> files)99     private void setFiles(List<FileInfo> files) {
100         mImageLoader.prePopulate(files.stream()
101                 .map(FileInfo::getPreviewUri)
102                 .filter(Objects::nonNull)
103                 .toList());
104         mFiles = files;
105         if (mContentPreviewView != null) {
106             updatePreviewWithFiles(mContentPreviewView, mHeadlineView, files);
107         }
108     }
109 
displayInternal( LayoutInflater layoutInflater, ViewGroup parent, View headlineViewParent)110     private ViewGroup displayInternal(
111             LayoutInflater layoutInflater, ViewGroup parent, View headlineViewParent) {
112         mContentPreviewView = (ViewGroup) layoutInflater.inflate(
113                 R.layout.chooser_grid_preview_image, parent, false);
114         mHeadlineView = headlineViewParent;
115         inflateHeadline(mHeadlineView);
116 
117         final ActionRow actionRow =
118                 mContentPreviewView.findViewById(com.android.internal.R.id.chooser_action_row);
119         List<ActionRow.Action> actions = mActionFactory.createCustomActions();
120         actionRow.setActions(actions);
121 
122         ScrollableImagePreviewView imagePreview =
123                 mContentPreviewView.requireViewById(R.id.scrollable_image_preview);
124         imagePreview.setImageLoader(mImageLoader);
125         imagePreview.setOnNoPreviewCallback(() -> imagePreview.setVisibility(View.GONE));
126         imagePreview.setTransitionElementStatusCallback(mTransitionElementStatusCallback);
127         imagePreview.setPreviews(
128                 JavaFlowHelper.mapFileIntoToPreview(
129                         mFileInfoFlow,
130                         mTypeClassifier,
131                         mShowEditAction ? mActionFactory.getEditButtonRunnable() : null),
132                 mItemCount);
133 
134         if (mFiles != null) {
135             updatePreviewWithFiles(mContentPreviewView, mHeadlineView, mFiles);
136         } else {
137             displayHeadline(
138                     mHeadlineView,
139                     mItemCount,
140                     mTypeClassifier.isImageType(mIntentMimeType),
141                     mTypeClassifier.isVideoType(mIntentMimeType));
142             imagePreview.setLoading(mItemCount);
143         }
144 
145         return mContentPreviewView;
146     }
147 
updatePreviewWithFiles( ViewGroup contentPreviewView, View headlineView, List<FileInfo> files)148     private void updatePreviewWithFiles(
149             ViewGroup contentPreviewView, View headlineView, List<FileInfo> files) {
150         final int count = files.size();
151         ScrollableImagePreviewView imagePreview =
152                 contentPreviewView.requireViewById(R.id.scrollable_image_preview);
153         if (count == 0) {
154             Log.i(
155                     TAG,
156                     "Attempted to display image preview area with zero"
157                             + " available images detected in EXTRA_STREAM list");
158             imagePreview.setVisibility(View.GONE);
159             mTransitionElementStatusCallback.onAllTransitionElementsReady();
160             return;
161         }
162 
163         boolean allImages = true;
164         boolean allVideos = true;
165         for (FileInfo fileInfo : files) {
166             ScrollableImagePreviewView.PreviewType previewType =
167                     getPreviewType(mTypeClassifier, fileInfo.getMimeType());
168             allImages = allImages && previewType == ScrollableImagePreviewView.PreviewType.Image;
169             allVideos = allVideos && previewType == ScrollableImagePreviewView.PreviewType.Video;
170         }
171 
172         displayHeadline(headlineView, count, allImages, allVideos);
173     }
174 
displayHeadline( View layout, int count, boolean allImages, boolean allVideos)175     private void displayHeadline(
176             View layout, int count, boolean allImages, boolean allVideos) {
177         if (allImages) {
178             displayHeadline(layout, mHeadlineGenerator.getImagesHeadline(count));
179         } else if (allVideos) {
180             displayHeadline(layout, mHeadlineGenerator.getVideosHeadline(count));
181         } else {
182             displayHeadline(layout, mHeadlineGenerator.getFilesHeadline(count));
183         }
184         displayMetadata(layout, mMetadata);
185     }
186 }
187