• 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 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