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.res.R 28 import java.io.IOException 29 30 data class ClipboardModel( 31 val clipData: ClipData, 32 val source: String, 33 val type: Type, 34 val text: CharSequence?, 35 val textLinks: TextLinks?, 36 val uri: Uri?, 37 val isSensitive: Boolean, 38 val isRemote: Boolean, 39 ) { 40 private var _bitmap: Bitmap? = null 41 dataMatchesnull42 fun dataMatches(other: ClipboardModel?): Boolean { 43 if (other == null) { 44 return false 45 } 46 return source == other.source && 47 type == other.type && 48 text == other.text && 49 uri == other.uri && 50 isSensitive == other.isSensitive 51 } 52 loadThumbnailnull53 fun loadThumbnail(context: Context): Bitmap? { 54 if (_bitmap == null && type == Type.IMAGE && uri != null) { 55 try { 56 val size = context.resources.getDimensionPixelSize(R.dimen.overlay_x_scale) 57 _bitmap = context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null) 58 } catch (e: IOException) { 59 Log.e(TAG, "Thumbnail loading failed!", e) 60 } 61 } 62 return _bitmap 63 } 64 65 internal companion object { 66 private val TAG: String = "ClipboardModel" 67 68 @JvmStatic fromClipDatanull69 fun fromClipData( 70 context: Context, 71 utils: ClipboardOverlayUtils, 72 clipData: ClipData, 73 source: String 74 ): ClipboardModel { 75 val sensitive = clipData.description?.extras?.getBoolean(EXTRA_IS_SENSITIVE) ?: false 76 val item = clipData.getItemAt(0)!! 77 val type = getType(context, item) 78 val remote = utils.isRemoteCopy(context, clipData, source) 79 return ClipboardModel( 80 clipData, 81 source, 82 type, 83 item.text, 84 item.textLinks, 85 item.uri, 86 sensitive, 87 remote 88 ) 89 } 90 getTypenull91 private fun getType(context: Context, item: ClipData.Item): Type { 92 return if (!TextUtils.isEmpty(item.text)) { 93 Type.TEXT 94 } else if (item.uri != null) { 95 if (context.contentResolver.getType(item.uri)?.startsWith("image") == true) { 96 Type.IMAGE 97 } else { 98 Type.URI 99 } 100 } else { 101 Type.OTHER 102 } 103 } 104 } 105 106 enum class Type { 107 TEXT, 108 IMAGE, 109 URI, 110 OTHER 111 } 112 } 113