зеркало из https://github.com/mozilla/gecko-dev.git
Bug 676268 - Part 1. Support text/html on Android clipboard backend r=geckoview-reviewers,snorp
Actually, we only support `text/unicode` mime type on Android clipboard backend. But Android API 16+ supports `text/html`, so we should support this type since Chrome/Blink already supports it. Differential Revision: https://phabricator.services.mozilla.com/D22659 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f934771efe
Коммит
61804ba4b3
|
@ -43,7 +43,6 @@ skip-if = toolkit == 'android'
|
|||
skip-if = toolkit == 'android'
|
||||
[test_bug410986.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug414526.html]
|
||||
[test_bug417418.html]
|
||||
skip-if = android_version == '18' # bug 1147989
|
||||
|
@ -61,11 +60,9 @@ skip-if = toolkit == 'android'
|
|||
[test_bug471722.html]
|
||||
[test_bug478725.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug480647.html]
|
||||
[test_bug480972.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug483651.html]
|
||||
[test_bug484181.html]
|
||||
skip-if = toolkit == 'android'
|
||||
|
@ -77,10 +74,8 @@ skip-if = toolkit == 'android' # bug 1299578
|
|||
[test_bug514156.html]
|
||||
[test_bug520189.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug525389.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug537046.html]
|
||||
[test_bug549262.html]
|
||||
skip-if = toolkit == 'android'
|
||||
|
@ -225,7 +220,6 @@ skip-if = os == 'android'
|
|||
[test_bug1230473.html]
|
||||
[test_bug1247483.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug1248128.html]
|
||||
[test_bug1250010.html]
|
||||
[test_bug1257363.html]
|
||||
|
@ -235,7 +229,6 @@ skip-if = toolkit == 'android'
|
|||
[test_bug1270235.html]
|
||||
[test_bug1306532.html]
|
||||
subsuite = clipboard
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug1310912.html]
|
||||
skip-if = toolkit == 'android' # bug 1315898
|
||||
[test_bug1314790.html]
|
||||
|
|
|
@ -8,37 +8,97 @@ import org.mozilla.gecko.annotation.WrapForJNI;
|
|||
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public final class Clipboard {
|
||||
private final static String HTML_MIME = "text/html";
|
||||
private final static String UNICODE_MIME = "text/unicode";
|
||||
private final static String LOGTAG = "GeckoClipboard";
|
||||
|
||||
private Clipboard() {
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
/**
|
||||
* Get the text on the primary clip on Android clipboard
|
||||
*
|
||||
* @param context application context.
|
||||
* @return a plain text string of clipboard data.
|
||||
*/
|
||||
public static String getText(final Context context) {
|
||||
return getData(context, UNICODE_MIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data on the primary clip on clipboard
|
||||
*
|
||||
* @param context application context
|
||||
* @param mimeType the mime type we want. This supports text/html and text/unicode only.
|
||||
* If other type, we do nothing.
|
||||
* @return a string into clipboard.
|
||||
*/
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
public static String getData(final Context context, final String mimeType) {
|
||||
final ClipboardManager cm = (ClipboardManager)
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm.hasPrimaryClip()) {
|
||||
ClipData clip = cm.getPrimaryClip();
|
||||
if (clip != null && clip.getItemCount() > 0) {
|
||||
ClipData.Item item = clip.getItemAt(0);
|
||||
return item.coerceToText(context).toString();
|
||||
if (clip == null || clip.getItemCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClipDescription description = clip.getDescription();
|
||||
if (HTML_MIME.equals(mimeType) && description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML)) {
|
||||
CharSequence data = clip.getItemAt(0).getHtmlText();
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return data.toString();
|
||||
}
|
||||
if (UNICODE_MIME.equals(mimeType)) {
|
||||
return clip.getItemAt(0).coerceToText(context).toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set plain text to clipboard
|
||||
*
|
||||
* @param context application context
|
||||
* @param text a plain text to set to clipboard
|
||||
*/
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
public static void setText(final Context context, final CharSequence text) {
|
||||
setData(context, ClipData.newPlainText("text", text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store HTML to clipboard
|
||||
*
|
||||
* @param context application context
|
||||
* @param text a plain text to set to clipboard
|
||||
* @param html a html text to set to clipboard
|
||||
*/
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
public static void setHTML(final Context context, final CharSequence text, final String htmlText) {
|
||||
setData(context, ClipData.newHtmlText("html", text, htmlText));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store {@link android.content.ClipData} to clipboard
|
||||
*
|
||||
* @param context application context
|
||||
* @param clipData a {@link android.content.ClipData} to set to clipboard
|
||||
*/
|
||||
private static void setData(final Context context, ClipData clipData) {
|
||||
// In API Level 11 and above, CLIPBOARD_SERVICE returns android.content.ClipboardManager,
|
||||
// which is a subclass of android.text.ClipboardManager.
|
||||
final ClipboardManager cm = (ClipboardManager)
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
try {
|
||||
cm.setPrimaryClip(ClipData.newPlainText("Text", text));
|
||||
cm.setPrimaryClip(clipData);
|
||||
} catch (NullPointerException e) {
|
||||
// Bug 776223: This is a Samsung clipboard bug. setPrimaryClip() can throw
|
||||
// a NullPointerException if Samsung's /data/clipboard directory is full.
|
||||
|
@ -50,8 +110,11 @@ public final class Clipboard {
|
|||
* @return true if the clipboard is nonempty, false otherwise.
|
||||
*/
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
public static boolean hasText(final Context context) {
|
||||
return !TextUtils.isEmpty(getText(context));
|
||||
public static boolean hasData(final Context context, final String mimeType) {
|
||||
if (HTML_MIME.equals(mimeType) || UNICODE_MIME.equals(mimeType)) {
|
||||
return !TextUtils.isEmpty(getData(context, mimeType));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -292,17 +292,6 @@ void AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType,
|
|||
}
|
||||
}
|
||||
|
||||
bool AndroidBridge::GetClipboardText(nsAString& aText) {
|
||||
ALOG_BRIDGE("AndroidBridge::GetClipboardText");
|
||||
|
||||
auto text = Clipboard::GetText(GeckoAppShell::GetApplicationContext());
|
||||
|
||||
if (text) {
|
||||
aText = text->ToString();
|
||||
}
|
||||
return !!text;
|
||||
}
|
||||
|
||||
int AndroidBridge::GetScreenDepth() {
|
||||
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
|
||||
|
||||
|
|
|
@ -113,8 +113,6 @@ class AndroidBridge final {
|
|||
void GetExtensionFromMimeType(const nsACString& aMimeType,
|
||||
nsACString& aFileExt);
|
||||
|
||||
bool GetClipboardText(nsAString& aText);
|
||||
|
||||
int GetScreenDepth();
|
||||
|
||||
void Vibrate(const nsTArray<uint32_t>& aPattern);
|
||||
|
|
|
@ -2,16 +2,14 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "FennecJNIWrappers.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsPrimitiveHelpers.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::dom::ContentChild;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard)
|
||||
|
||||
|
@ -28,52 +26,100 @@ nsClipboard::SetData(nsITransferable *aTransferable, nsIClipboardOwner *anOwner,
|
|||
int32_t aWhichClipboard) {
|
||||
if (aWhichClipboard != kGlobalClipboard) return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
nsresult rv =
|
||||
aTransferable->GetTransferData(kUnicodeMime, getter_AddRefs(tmp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(tmp);
|
||||
// No support for non-text data
|
||||
NS_ENSURE_TRUE(supportsString, NS_ERROR_NOT_IMPLEMENTED);
|
||||
nsAutoString buffer;
|
||||
supportsString->GetData(buffer);
|
||||
if (!jni::IsAvailable()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
java::Clipboard::SetText(java::GeckoAppShell::GetApplicationContext(),
|
||||
buffer);
|
||||
return NS_OK;
|
||||
nsTArray<nsCString> flavors;
|
||||
aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
|
||||
nsAutoString html;
|
||||
nsAutoString text;
|
||||
|
||||
for (auto &flavorStr : flavors) {
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
||||
nsCOMPtr<nsISupports> item;
|
||||
nsresult rv =
|
||||
aTransferable->GetTransferData(kUnicodeMime, getter_AddRefs(item));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(item);
|
||||
if (supportsString) {
|
||||
supportsString->GetData(text);
|
||||
}
|
||||
} else if (flavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
nsCOMPtr<nsISupports> item;
|
||||
nsresult rv =
|
||||
aTransferable->GetTransferData(kHTMLMime, getter_AddRefs(item));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(item);
|
||||
if (supportsString) {
|
||||
supportsString->GetData(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!html.IsEmpty()) {
|
||||
java::Clipboard::SetHTML(GeckoAppShell::GetApplicationContext(), text,
|
||||
html);
|
||||
return NS_OK;
|
||||
}
|
||||
if (!text.IsEmpty()) {
|
||||
java::Clipboard::SetText(GeckoAppShell::GetApplicationContext(), text);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard) {
|
||||
if (aWhichClipboard != kGlobalClipboard) return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
nsAutoString buffer;
|
||||
if (!AndroidBridge::Bridge()) return NS_ERROR_NOT_IMPLEMENTED;
|
||||
if (!AndroidBridge::Bridge()->GetClipboardText(buffer))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
if (!jni::IsAvailable()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsTArray<nsCString> flavors;
|
||||
aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
|
||||
rv = dataWrapper->SetData(buffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (auto &flavorStr : flavors) {
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime) ||
|
||||
flavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
auto text =
|
||||
Clipboard::GetData(GeckoAppShell::GetApplicationContext(), flavorStr);
|
||||
if (!text) {
|
||||
continue;
|
||||
}
|
||||
nsString buffer = text->ToString();
|
||||
if (buffer.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, buffer.get(),
|
||||
buffer.Length() * 2,
|
||||
getter_AddRefs(wrapper));
|
||||
if (wrapper) {
|
||||
aTransferable->SetTransferData(flavorStr.get(), wrapper);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If our data flavor has already been added, this will fail. But we don't
|
||||
// care
|
||||
aTransferable->AddDataFlavor(kUnicodeMime);
|
||||
|
||||
nsCOMPtr<nsISupports> nsisupportsDataWrapper = do_QueryInterface(dataWrapper);
|
||||
rv = aTransferable->SetTransferData(kUnicodeMime, nsisupportsDataWrapper);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::EmptyClipboard(int32_t aWhichClipboard) {
|
||||
if (aWhichClipboard != kGlobalClipboard) return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if (!jni::IsAvailable()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
java::Clipboard::ClearText(java::GeckoAppShell::GetApplicationContext());
|
||||
|
||||
return NS_OK;
|
||||
|
@ -85,11 +131,17 @@ nsClipboard::HasDataMatchingFlavors(const char **aFlavorList, uint32_t aLength,
|
|||
*aHasText = false;
|
||||
if (aWhichClipboard != kGlobalClipboard) return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if (!jni::IsAvailable()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
for (uint32_t k = 0; k < aLength; k++) {
|
||||
if (strcmp(aFlavorList[k], kUnicodeMime) == 0) {
|
||||
*aHasText = java::Clipboard::HasText(
|
||||
java::GeckoAppShell::GetApplicationContext());
|
||||
break;
|
||||
bool hasData =
|
||||
java::Clipboard::HasData(java::GeckoAppShell::GetApplicationContext(),
|
||||
NS_ConvertASCIItoUTF16(aFlavorList[k]));
|
||||
if (hasData) {
|
||||
*aHasText = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче