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