• 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.util.UriFilters.isOwnedByCurrentUser;
20 
21 import android.content.res.Resources;
22 import android.net.Uri;
23 import android.text.SpannableStringBuilder;
24 import android.text.TextUtils;
25 import android.util.Size;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.ImageView;
30 import android.widget.TextView;
31 
32 import androidx.annotation.Nullable;
33 import androidx.core.view.ViewCompat;
34 
35 import com.android.intentresolver.ContentTypeHint;
36 import com.android.intentresolver.R;
37 import com.android.intentresolver.widget.ActionRow;
38 import com.android.intentresolver.widget.ViewRoleDescriptionAccessibilityDelegate;
39 
40 import kotlinx.coroutines.CoroutineScope;
41 
42 class TextContentPreviewUi extends ContentPreviewUi {
43     private final CoroutineScope mScope;
44     @Nullable
45     private final CharSequence mSharingText;
46     @Nullable
47     private final CharSequence mPreviewTitle;
48     @Nullable
49     private final CharSequence mMetadata;
50     @Nullable
51     private final Uri mPreviewThumbnail;
52     private final ImageLoader mImageLoader;
53     private final ChooserContentPreviewUi.ActionFactory mActionFactory;
54     private final HeadlineGenerator mHeadlineGenerator;
55     private final ContentTypeHint mContentTypeHint;
56     private int mPreviewSize;
57 
TextContentPreviewUi( CoroutineScope scope, @Nullable CharSequence sharingText, @Nullable CharSequence previewTitle, @Nullable CharSequence metadata, @Nullable Uri previewThumbnail, ChooserContentPreviewUi.ActionFactory actionFactory, ImageLoader imageLoader, HeadlineGenerator headlineGenerator, ContentTypeHint contentTypeHint)58     TextContentPreviewUi(
59             CoroutineScope scope,
60             @Nullable CharSequence sharingText,
61             @Nullable CharSequence previewTitle,
62             @Nullable CharSequence metadata,
63             @Nullable Uri previewThumbnail,
64             ChooserContentPreviewUi.ActionFactory actionFactory,
65             ImageLoader imageLoader,
66             HeadlineGenerator headlineGenerator,
67             ContentTypeHint contentTypeHint) {
68         mScope = scope;
69         mSharingText = sharingText;
70         mPreviewTitle = previewTitle;
71         mMetadata = metadata;
72         mPreviewThumbnail = previewThumbnail;
73         mImageLoader = imageLoader;
74         mActionFactory = actionFactory;
75         mHeadlineGenerator = headlineGenerator;
76         mContentTypeHint = contentTypeHint;
77     }
78 
79     @Override
getType()80     public int getType() {
81         return ContentPreviewType.CONTENT_PREVIEW_TEXT;
82     }
83 
84     @Override
display( Resources resources, LayoutInflater layoutInflater, ViewGroup parent, View headlineViewParent)85     public ViewGroup display(
86             Resources resources,
87             LayoutInflater layoutInflater,
88             ViewGroup parent,
89             View headlineViewParent) {
90         mPreviewSize = resources.getDimensionPixelSize(R.dimen.width_text_image_preview_size);
91         return displayInternal(layoutInflater, parent, headlineViewParent);
92     }
93 
displayInternal( LayoutInflater layoutInflater, ViewGroup parent, View headlineViewParent)94     private ViewGroup displayInternal(
95             LayoutInflater layoutInflater,
96             ViewGroup parent,
97             View headlineViewParent) {
98         ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
99                 R.layout.chooser_grid_preview_text, parent, false);
100         inflateHeadline(headlineViewParent);
101 
102         final ActionRow actionRow =
103                 contentPreviewLayout.findViewById(com.android.internal.R.id.chooser_action_row);
104         actionRow.setActions(mActionFactory.createCustomActions());
105 
106         if (mSharingText == null) {
107             contentPreviewLayout
108                     .findViewById(R.id.text_preview_layout)
109                     .setVisibility(View.GONE);
110             return contentPreviewLayout;
111         }
112 
113         TextView textView = contentPreviewLayout.findViewById(
114                 com.android.internal.R.id.content_preview_text);
115 
116         textView.setText(
117                 textView.getMaxLines() == 1 ? replaceLineBreaks(mSharingText) : mSharingText);
118 
119         TextView previewTitleView = contentPreviewLayout.findViewById(
120                 com.android.internal.R.id.content_preview_title);
121         if (TextUtils.isEmpty(mPreviewTitle)) {
122             previewTitleView.setVisibility(View.GONE);
123         } else {
124             previewTitleView.setText(mPreviewTitle);
125         }
126 
127         final ImageView previewThumbnailView = contentPreviewLayout.requireViewById(
128                 com.android.internal.R.id.content_preview_thumbnail);
129         if (!isOwnedByCurrentUser(mPreviewThumbnail)) {
130             previewThumbnailView.setVisibility(View.GONE);
131         } else {
132             mImageLoader.loadImage(
133                     mScope,
134                     mPreviewThumbnail,
135                     new Size(mPreviewSize, mPreviewSize),
136                     (bitmap) -> updateViewWithImage(
137                             previewThumbnailView,
138                             bitmap));
139         }
140 
141         Runnable onCopy = mActionFactory.getCopyButtonRunnable();
142         View copyButton = contentPreviewLayout.findViewById(R.id.copy);
143         if (copyButton != null) {
144             if (onCopy != null) {
145                 copyButton.setContentDescription(
146                         mHeadlineGenerator.getCopyButtonContentDescription(mSharingText));
147                 copyButton.setOnClickListener((v) -> onCopy.run());
148                 ViewCompat.setAccessibilityDelegate(
149                         copyButton,
150                         new ViewRoleDescriptionAccessibilityDelegate(
151                                 layoutInflater.getContext()
152                                         .getString(R.string.role_description_button)));
153             } else {
154                 copyButton.setVisibility(View.GONE);
155             }
156         }
157 
158         String headlineText = (mContentTypeHint == ContentTypeHint.ALBUM)
159                 ? mHeadlineGenerator.getAlbumHeadline()
160                 : mHeadlineGenerator.getTextHeadline(mSharingText);
161         displayHeadline(headlineViewParent, headlineText);
162         displayMetadata(headlineViewParent, mMetadata);
163 
164         return contentPreviewLayout;
165     }
166 
167     @Nullable
replaceLineBreaks(@ullable CharSequence text)168     private static CharSequence replaceLineBreaks(@Nullable CharSequence text) {
169         if (text == null) {
170             return null;
171         }
172         SpannableStringBuilder string = new SpannableStringBuilder(text);
173         for (int i = 0, size = string.length(); i < size; i++) {
174             if (string.charAt(i) == '\n') {
175                 string.replace(i, i + 1, " ");
176             }
177         }
178         return string;
179     }
180 }
181