Android: Add support for setting/getting html and uris from clipboard
This also updates the used API to use ClipData and not the deprecated ClipboardManager API. [ChangeLog][Platform Specific Changes][Android] QClipboard now supports HTML and URI data. Fixes: QTBUG-47835 Fixes: QTBUG-71503 Change-Id: I43f82bfc63b3d159087c0fb6c840c186a370e20c Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
parent
28b2232e78
commit
4aac07d023
@ -47,6 +47,7 @@ import java.util.concurrent.Semaphore;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
@ -57,6 +58,7 @@ import android.os.IBinder;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.ClipboardManager.OnPrimaryClipChangedListener;
|
import android.content.ClipboardManager.OnPrimaryClipChangedListener;
|
||||||
|
import android.content.ClipData;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@ -98,7 +100,9 @@ public class QtNative
|
|||||||
private static ClipboardManager m_clipboardManager = null;
|
private static ClipboardManager m_clipboardManager = null;
|
||||||
private static Method m_checkSelfPermissionMethod = null;
|
private static Method m_checkSelfPermissionMethod = null;
|
||||||
private static Boolean m_tabletEventSupported = null;
|
private static Boolean m_tabletEventSupported = null;
|
||||||
|
private static boolean m_usePrimaryClip = false;
|
||||||
public static QtThread m_qtThread = new QtThread();
|
public static QtThread m_qtThread = new QtThread();
|
||||||
|
private static Method m_addItemMethod = null;
|
||||||
private static final Runnable runPendingCppRunnablesRunnable = new Runnable() {
|
private static final Runnable runPendingCppRunnablesRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -697,28 +701,135 @@ public class QtNative
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void clearClipData()
|
||||||
|
{
|
||||||
|
m_usePrimaryClip = false;
|
||||||
|
}
|
||||||
private static void setClipboardText(String text)
|
private static void setClipboardText(String text)
|
||||||
{
|
{
|
||||||
if (m_clipboardManager != null)
|
if (m_clipboardManager != null) {
|
||||||
m_clipboardManager.setText(text);
|
ClipData clipData = ClipData.newPlainText("text/plain", text);
|
||||||
|
updatePrimaryClip(clipData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasClipboardText()
|
public static boolean hasClipboardText()
|
||||||
{
|
{
|
||||||
if (m_clipboardManager != null)
|
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
|
||||||
return m_clipboardManager.hasText();
|
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
|
||||||
else
|
for (int i = 0; i < primaryClip.getItemCount(); ++i)
|
||||||
|
if (primaryClip.getItemAt(i).getText() != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getClipboardText()
|
private static String getClipboardText()
|
||||||
{
|
{
|
||||||
if (m_clipboardManager != null)
|
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
|
||||||
return m_clipboardManager.getText().toString();
|
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
|
||||||
else
|
for (int i = 0; i < primaryClip.getItemCount(); ++i)
|
||||||
|
if (primaryClip.getItemAt(i).getText() != null)
|
||||||
|
return primaryClip.getItemAt(i).getText().toString();
|
||||||
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void updatePrimaryClip(ClipData clipData)
|
||||||
|
{
|
||||||
|
if (m_usePrimaryClip) {
|
||||||
|
ClipData clip = m_clipboardManager.getPrimaryClip();
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
if (m_addItemMethod == null) {
|
||||||
|
Class[] cArg = new Class[2];
|
||||||
|
cArg[0] = ContentResolver.class;
|
||||||
|
cArg[1] = ClipData.Item.class;
|
||||||
|
try {
|
||||||
|
m_addItemMethod = m_clipboardManager.getClass().getMethod("addItem", cArg);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_addItemMethod != null) {
|
||||||
|
try {
|
||||||
|
m_addItemMethod.invoke(m_activity.getContentResolver(), clipData.getItemAt(0));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clip.addItem(clipData.getItemAt(0));
|
||||||
|
}
|
||||||
|
m_clipboardManager.setPrimaryClip(clip);
|
||||||
|
} else {
|
||||||
|
m_clipboardManager.setPrimaryClip(clipData);
|
||||||
|
m_usePrimaryClip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setClipboardHtml(String text, String html)
|
||||||
|
{
|
||||||
|
if (m_clipboardManager != null) {
|
||||||
|
ClipData clipData = ClipData.newHtmlText("text/html", text, html);
|
||||||
|
updatePrimaryClip(clipData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasClipboardHtml()
|
||||||
|
{
|
||||||
|
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
|
||||||
|
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
|
||||||
|
for (int i = 0; i < primaryClip.getItemCount(); ++i)
|
||||||
|
if (primaryClip.getItemAt(i).getHtmlText() != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getClipboardHtml()
|
||||||
|
{
|
||||||
|
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
|
||||||
|
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
|
||||||
|
for (int i = 0; i < primaryClip.getItemCount(); ++i)
|
||||||
|
if (primaryClip.getItemAt(i).getHtmlText() != null)
|
||||||
|
return primaryClip.getItemAt(i).getHtmlText().toString();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setClipboardUri(String uriString)
|
||||||
|
{
|
||||||
|
if (m_clipboardManager != null) {
|
||||||
|
ClipData clipData = ClipData.newUri(m_activity.getContentResolver(), "text/uri-list",
|
||||||
|
Uri.parse(uriString));
|
||||||
|
updatePrimaryClip(clipData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasClipboardUri()
|
||||||
|
{
|
||||||
|
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
|
||||||
|
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
|
||||||
|
for (int i = 0; i < primaryClip.getItemCount(); ++i)
|
||||||
|
if (primaryClip.getItemAt(i).getUri() != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] getClipboardUris()
|
||||||
|
{
|
||||||
|
ArrayList<String> uris = new ArrayList<String>();
|
||||||
|
if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
|
||||||
|
ClipData primaryClip = m_clipboardManager.getPrimaryClip();
|
||||||
|
for (int i = 0; i < primaryClip.getItemCount(); ++i)
|
||||||
|
if (primaryClip.getItemAt(i).getUri() != null)
|
||||||
|
uris.add(primaryClip.getItemAt(i).getUri().toString());
|
||||||
|
}
|
||||||
|
String[] strings = new String[uris.size()];
|
||||||
|
strings = uris.toArray(strings);
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
private static void openContextMenu(final int x, final int y, final int w, final int h)
|
private static void openContextMenu(final int x, final int y, final int w, final int h)
|
||||||
{
|
{
|
||||||
runAction(new Runnable() {
|
runAction(new Runnable() {
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "androidjniclipboard.h"
|
#include "androidjniclipboard.h"
|
||||||
|
#include <QtCore/QUrl>
|
||||||
#include <QtCore/private/qjni_p.h>
|
#include <QtCore/private/qjni_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -62,27 +63,60 @@ namespace QtAndroidClipboard
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void setClipboardMimeData(QMimeData *data)
|
||||||
void setClipboardText(const QString &text)
|
|
||||||
{
|
{
|
||||||
|
QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "clearClipData");
|
||||||
|
if (data->hasText()) {
|
||||||
QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
|
QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
|
||||||
"setClipboardText",
|
"setClipboardText", "(Ljava/lang/String;)V",
|
||||||
|
QJNIObjectPrivate::fromString(data->text()).object());
|
||||||
|
}
|
||||||
|
if (data->hasHtml()) {
|
||||||
|
QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
|
||||||
|
"setClipboardHtml",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;)V",
|
||||||
|
QJNIObjectPrivate::fromString(data->text()).object(),
|
||||||
|
QJNIObjectPrivate::fromString(data->html()).object());
|
||||||
|
}
|
||||||
|
if (data->hasUrls()) {
|
||||||
|
QList<QUrl> urls = data->urls();
|
||||||
|
for (const auto &u : qAsConst(urls)) {
|
||||||
|
QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "setClipboardUri",
|
||||||
"(Ljava/lang/String;)V",
|
"(Ljava/lang/String;)V",
|
||||||
QJNIObjectPrivate::fromString(text).object());
|
QJNIObjectPrivate::fromString(u.toEncoded()).object());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasClipboardText()
|
QMimeData *getClipboardMimeData()
|
||||||
{
|
{
|
||||||
return QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(),
|
QMimeData *data = new QMimeData;
|
||||||
"hasClipboardText");
|
if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardText")) {
|
||||||
}
|
data->setText(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
|
||||||
|
|
||||||
QString clipboardText()
|
|
||||||
{
|
|
||||||
QJNIObjectPrivate text = QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
|
|
||||||
"getClipboardText",
|
"getClipboardText",
|
||||||
"()Ljava/lang/String;");
|
"()Ljava/lang/String;").toString());
|
||||||
return text.toString();
|
}
|
||||||
|
if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardHtml")) {
|
||||||
|
data->setHtml(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
|
||||||
|
"getClipboardHtml",
|
||||||
|
"()Ljava/lang/String;").toString());
|
||||||
|
}
|
||||||
|
if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardUri")) {
|
||||||
|
QJNIObjectPrivate uris = QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
|
||||||
|
"getClipboardUris",
|
||||||
|
"()[Ljava/lang/String;");
|
||||||
|
if (uris.isValid()) {
|
||||||
|
QList<QUrl> urls;
|
||||||
|
QJNIEnvironmentPrivate env;
|
||||||
|
jobjectArray juris = static_cast<jobjectArray>(uris.object());
|
||||||
|
const jint nUris = env->GetArrayLength(juris);
|
||||||
|
urls.reserve(static_cast<int>(nUris));
|
||||||
|
for (int i = 0; i < nUris; ++i)
|
||||||
|
urls << QUrl(QJNIObjectPrivate(env->GetObjectArrayElement(juris, i)).toString());
|
||||||
|
data->setUrls(urls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/)
|
void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/)
|
||||||
|
@ -51,9 +51,8 @@ namespace QtAndroidClipboard
|
|||||||
{
|
{
|
||||||
// Clipboard support
|
// Clipboard support
|
||||||
void setClipboardManager(QAndroidPlatformClipboard *manager);
|
void setClipboardManager(QAndroidPlatformClipboard *manager);
|
||||||
void setClipboardText(const QString &text);
|
void setClipboardMimeData(QMimeData *data);
|
||||||
bool hasClipboardText();
|
QMimeData *getClipboardMimeData();
|
||||||
QString clipboardText();
|
|
||||||
void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/);
|
void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/);
|
||||||
// Clipboard support
|
// Clipboard support
|
||||||
}
|
}
|
||||||
|
@ -52,16 +52,15 @@ QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(mode);
|
Q_UNUSED(mode);
|
||||||
Q_ASSERT(supportsMode(mode));
|
Q_ASSERT(supportsMode(mode));
|
||||||
m_mimeData.setText(QtAndroidClipboard::hasClipboardText()
|
QMimeData *data = QtAndroidClipboard::getClipboardMimeData();
|
||||||
? QtAndroidClipboard::clipboardText()
|
data->setParent(this);
|
||||||
: QString());
|
return data;
|
||||||
return &m_mimeData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
|
void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
|
||||||
{
|
{
|
||||||
if (supportsMode(mode))
|
if (data && supportsMode(mode))
|
||||||
QtAndroidClipboard::setClipboardText(data != 0 && data->hasText() ? data->text() : QString());
|
QtAndroidClipboard::setClipboardMimeData(data);
|
||||||
if (data != 0)
|
if (data != 0)
|
||||||
data->deleteLater();
|
data->deleteLater();
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
#ifndef QT_NO_CLIPBOARD
|
#ifndef QT_NO_CLIPBOARD
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QAndroidPlatformClipboard: public QPlatformClipboard
|
class QAndroidPlatformClipboard : public QObject, public QPlatformClipboard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QAndroidPlatformClipboard();
|
QAndroidPlatformClipboard();
|
||||||
@ -54,9 +54,6 @@ public:
|
|||||||
QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
|
QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
|
||||||
void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
|
void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
|
||||||
bool supportsMode(QClipboard::Mode mode) const override;
|
bool supportsMode(QClipboard::Mode mode) const override;
|
||||||
|
|
||||||
private:
|
|
||||||
QMimeData m_mimeData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
Loading…
Reference in New Issue
Block a user