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 package com.android.systemui.clipboardoverlay 17 18 import android.content.ClipData 19 import android.content.ClipDescription.EXTRA_IS_SENSITIVE 20 import android.content.Context 21 import android.graphics.Bitmap 22 import android.net.Uri 23 import android.text.TextUtils 24 import android.util.Log 25 import android.util.Size 26 import android.view.textclassifier.TextLinks 27 import com.android.systemui.Flags.clipboardUseDescriptionMimetype 28 import com.android.systemui.res.R 29 import java.io.IOException 30 31 data class ClipboardModel( 32 val clipData: ClipData, 33 val source: String, 34 val type: Type, 35 val text: CharSequence?, 36 val textLinks: TextLinks?, 37 val uri: Uri?, 38 val isSensitive: Boolean, 39 val isRemote: Boolean, 40 ) { 41 private var _bitmap: Bitmap? = null 42 dataMatchesnull43 fun dataMatches(other: ClipboardModel?): Boolean { 44 if (other == null) { 45 return false 46 } 47 return source == other.source && 48 type == other.type && 49 text == other.text && 50 uri == other.uri && 51 isSensitive == other.isSensitive 52 } 53 loadThumbnailnull54 fun loadThumbnail(context: Context): Bitmap? { 55 if (_bitmap == null && type == Type.IMAGE && uri != null) { 56 try { 57 val size = context.resources.getDimensionPixelSize(R.dimen.overlay_x_scale) 58 _bitmap = context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null) 59 } catch (e: IOException) { 60 Log.e(TAG, "Thumbnail loading failed!", e) 61 } 62 } 63 return _bitmap 64 } 65 66 internal companion object { 67 private val TAG: String = "ClipboardModel" 68 69 @JvmStatic fromClipDatanull70 fun fromClipData( 71 context: Context, 72 utils: ClipboardOverlayUtils, 73 clipData: ClipData, 74 source: String, 75 ): ClipboardModel { 76 val sensitive = clipData.description?.extras?.getBoolean(EXTRA_IS_SENSITIVE) ?: false 77 val item = clipData.getItemAt(0)!! 78 val type = getType(context, item, clipData.description.getMimeType(0)) 79 val remote = utils.isRemoteCopy(context, clipData, source) 80 return ClipboardModel( 81 clipData, 82 source, 83 type, 84 item.text, 85 item.textLinks, 86 item.uri, 87 sensitive, 88 remote, 89 ) 90 } 91 getTypenull92 private fun getType(context: Context, item: ClipData.Item, mimeType: String): Type { 93 return if (!TextUtils.isEmpty(item.text)) { 94 Type.TEXT 95 } else if (item.uri != null) { 96 if (clipboardUseDescriptionMimetype()) { 97 if (mimeType.startsWith("image")) { 98 Type.IMAGE 99 } else { 100 Type.URI 101 } 102 } else { 103 if (context.contentResolver.getType(item.uri)?.startsWith("image") == true) { 104 Type.IMAGE 105 } else { 106 Type.URI 107 } 108 } 109 } else { 110 Type.OTHER 111 } 112 } 113 } 114 115 enum class Type { 116 TEXT, 117 IMAGE, 118 URI, 119 OTHER, 120 } 121 } 122