5package org.qtproject.qt.android;
7import android.app.Activity;
8import android.content.ClipData;
9import android.content.ClipDescription;
10import android.graphics.Bitmap;
11import android.graphics.Canvas;
12import android.graphics.Point;
13import android.net.Uri;
14import android.util.Log;
15import android.view.DragAndDropPermissions;
16import android.view.DragEvent;
17import android.view.View;
19import java.util.Arrays;
21class QtDragManager
implements View.OnDragListener
23 private static final String TAG =
"QtDragManager";
24 private static final String DEFAULT_MIME_TYPE =
"application/octet-stream";
26 private static QtDragManager m_instance =
null;
28 private volatile long m_nativePointer = 0;
29 private volatile View m_sourceView =
null;
30 private DragAndDropPermissions m_dragPermissions =
null;
32 static native
boolean onDragEvent(
long nativePointer,
int viewId,
int action,
float x,
float y,
36 static synchronized QtDragManager getInstance()
38 if (m_instance ==
null)
39 m_instance =
new QtDragManager();
44 static synchronized void setNativePointer(
long nativePointer)
46 getInstance().m_nativePointer = nativePointer;
50 static synchronized void clearNativePointer(
long expected)
52 final QtDragManager instance = getInstance();
53 if (instance.m_nativePointer ==
expected) {
54 instance.m_nativePointer = 0;
58 instance.m_sourceView =
null;
63 void startDrag(QtWindow sourceWindow,
String[] mimeTypes,
String[] clipData,
64 Bitmap shadowBitmap,
int hotSpotX,
int hotSpotY)
66 if (sourceWindow ==
null)
70 QtNative.runAction(() -> {
71 boolean started =
false;
77 boolean hasContentUri =
false;
78 for (
int i = 0;
i < mimeTypes.length; ++
i) {
80 final String mime = mimeTypes[
i];
81 if (mime.equals(ClipDescription.MIMETYPE_TEXT_HTML)) {
83 }
else if (mime.equals(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
85 }
else if (mime.equals(ClipDescription.MIMETYPE_TEXT_URILIST)
88 if (!
first.isEmpty()) {
90 uri = Uri.parse(
first);
91 hasContentUri =
"content".equals(uri.getScheme());
96 boolean hasMimeTypes = mimeTypes.length > 0;
98 ClipData.Item item =
new ClipData.Item(text, html,
null, uri);
99 ClipData clip =
new ClipData(
new ClipDescription(
"DragClip",
types), item);
101 if (uriListData !=
null) {
102 final String[] parts = uriListData.split(
"[\\r\\n]+");
103 for (
int i = 1;
i < parts.length; ++
i) {
104 final String part = parts[
i].trim();
105 if (!part.isEmpty()) {
106 final Uri extraUri = Uri.parse(part);
107 hasContentUri |=
"content".equals(extraUri.getScheme());
108 clip.addItem(
new ClipData.Item(extraUri));
112 View.DragShadowBuilder shadow =
new QtDragShadowBuilder(sourceWindow, shadowBitmap,
114 m_sourceView = sourceWindow;
117 int flags = View.DRAG_FLAG_GLOBAL;
119 flags |= View.DRAG_FLAG_GLOBAL_URI_READ;
121 started = sourceWindow.startDragAndDrop(clip, shadow, QtDragManager.this,
flags);
122 }
catch (Exception e) {
123 Log.e(TAG,
"startDragAndDrop() failed on window id " + sourceWindow.getId(), e);
129 final long ptr = m_nativePointer;
132 onDragEvent(
ptr, sourceWindow.getId(), DragEvent.ACTION_DRAG_ENDED,
133 0
f, 0
f, empty, empty,
false);
142 QtNative.runAction(() -> {
143 if (m_sourceView !=
null)
144 m_sourceView.cancelDragAndDrop();
148 private void releaseDragPermissions()
150 if (m_dragPermissions !=
null) {
151 m_dragPermissions.release();
152 m_dragPermissions =
null;
156 void onSourceWindowDetached(View
view)
158 if (m_sourceView !=
view)
161 final long ptr = m_nativePointer;
164 onDragEvent(
ptr,
view.getId(), DragEvent.ACTION_DRAG_ENDED, 0
f, 0
f, empty, empty,
false);
169 public boolean onDrag(View
view, DragEvent
event)
171 final int action =
event.getAction();
173 if (action == DragEvent.ACTION_DRAG_ENDED) {
175 releaseDragPermissions();
178 final long nativePointer = m_nativePointer;
179 if (nativePointer == 0)
182 if (action == DragEvent.ACTION_DRAG_STARTED)
187 final ClipDescription description =
event.getClipDescription();
188 if (description !=
null) {
189 final int size = description.getMimeTypeCount();
191 for (
int i = 0;
i <
size; ++
i)
192 mimeTypes[i] = description.getMimeType(i);
196 if (action == DragEvent.ACTION_DROP) {
198 final ClipData clip =
event.getClipData();
199 if (clip !=
null && clip.getItemCount() > 0) {
200 clipData =
new String[mimeTypes.length];
201 Arrays.fill(clipData,
"");
203 StringBuilder uriList =
new StringBuilder();
204 for (
int i = 0;
i < clip.getItemCount(); ++
i) {
205 Uri itemUri = clip.getItemAt(i).getUri();
206 if (itemUri !=
null) {
207 if (uriList.length() > 0)
208 uriList.append(
'\n');
209 uriList.append(itemUri.toString());
212 if (uriList.length() > 0) {
213 releaseDragPermissions();
214 final Activity
activity = QtNative.activity();
215 if (activity !=
null) {
216 m_dragPermissions =
activity.requestDragAndDropPermissions(
event);
217 if (m_dragPermissions ==
null)
218 Log.w(TAG,
"Drag and drop reading permissions denied.");
223 ClipData.Item item = clip.getItemAt(0);
224 for (
int i = 0;
i < mimeTypes.length; ++
i) {
225 if (ClipDescription.MIMETYPE_TEXT_HTML.equals(mimeTypes[i])) {
226 final String html = item.getHtmlText();
227 clipData[
i] = (html !=
null) ? html :
"";
228 }
else if (ClipDescription.MIMETYPE_TEXT_URILIST.equals(mimeTypes[i])) {
229 clipData[
i] = uriList.toString();
230 }
else if (ClipDescription.MIMETYPE_TEXT_PLAIN.equals(mimeTypes[i])) {
232 CharSequence
text = item.getText();
234 text = item.coerceToText(
view.getContext());
235 clipData[
i] = (
text !=
null) ?
text.toString() :
"";
237 final Uri itemUri = item.getUri();
238 if (itemUri !=
null) {
239 clipData[
i] = itemUri.toString();
241 final CharSequence
text = item.coerceToText(
view.getContext());
242 clipData[
i] = (
text !=
null) ?
text.toString() :
"";
247 }
catch (Exception e) {
248 Log.e(TAG,
"Failed to read dropped clip data", e);
252 return onDragEvent(nativePointer,
view.getId(), action,
event.getX(),
event.getY(),
253 mimeTypes, clipData,
event.getResult());
256 private static class QtDragShadowBuilder
extends View.DragShadowBuilder
258 private final Bitmap m_bitmap;
259 private final int m_hotSpotX;
260 private final int m_hotSpotY;
262 QtDragShadowBuilder(View
view, Bitmap
bitmap,
int hotSpotX,
int hotSpotY)
266 m_hotSpotX = hotSpotX;
267 m_hotSpotY = hotSpotY;
271 public void onProvideShadowMetrics(
Point outShadowSize,
Point outShadowTouchPoint)
273 if (m_bitmap ==
null) {
274 super.onProvideShadowMetrics(outShadowSize, outShadowTouchPoint);
278 outShadowSize.set(m_bitmap.getWidth(), m_bitmap.getHeight());
279 outShadowTouchPoint.set(m_hotSpotX, m_hotSpotY);
283 public void onDrawShadow(Canvas canvas)
285 if (m_bitmap !=
null)
286 canvas.drawBitmap(m_bitmap, 0, 0,
null);
Q_CORE_EXPORT QtJniTypes::Activity activity()
static ControlElement< T > * ptr(QWidget *widget)
GLint GLint GLint GLint GLint x
GLsizei GLenum GLenum * types
GLenum GLuint GLintptr GLsizeiptr size
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
[0]
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap