mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 876485 - Moved clipboard code from GeckoAppShell to a separate Clipboard class. Changed jni calls to new methods. r=cpeterson
This commit is contained in:
parent
d775786d2c
commit
55bcb1df9b
@ -15,6 +15,7 @@ import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.gfx.PanZoomController;
|
||||
import org.mozilla.gecko.health.BrowserHealthReporter;
|
||||
import org.mozilla.gecko.menu.GeckoMenu;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.FloatUtils;
|
||||
import org.mozilla.gecko.util.GamepadUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
@ -510,7 +511,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case R.id.pasteandgo: {
|
||||
String text = GeckoAppShell.getClipboardText();
|
||||
String text = Clipboard.getText();
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
Tabs.getInstance().loadUrl(text);
|
||||
}
|
||||
@ -521,7 +522,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
return true;
|
||||
}
|
||||
case R.id.paste: {
|
||||
String text = GeckoAppShell.getClipboardText();
|
||||
String text = Clipboard.getText();
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
showAwesomebar(AwesomeBar.Target.CURRENT_TAB, text);
|
||||
}
|
||||
@ -549,7 +550,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
if (tab != null) {
|
||||
String url = tab.getURL();
|
||||
if (url != null) {
|
||||
GeckoAppShell.setClipboardText(url);
|
||||
Clipboard.setText(url);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -11,6 +11,7 @@ import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.menu.GeckoMenu;
|
||||
import org.mozilla.gecko.menu.MenuPopup;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
|
||||
@ -198,7 +199,7 @@ public class BrowserToolbar implements Tabs.OnTabsChangedListener,
|
||||
MenuInflater inflater = mActivity.getMenuInflater();
|
||||
inflater.inflate(R.menu.titlebar_contextmenu, menu);
|
||||
|
||||
String clipboard = GeckoAppShell.getClipboardText();
|
||||
String clipboard = Clipboard.getText();
|
||||
if (TextUtils.isEmpty(clipboard)) {
|
||||
menu.findItem(R.id.pasteandgo).setVisible(false);
|
||||
menu.findItem(R.id.paste).setVisible(false);
|
||||
|
@ -20,7 +20,6 @@ import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@ -102,7 +101,6 @@ import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
public class GeckoAppShell
|
||||
{
|
||||
@ -1231,85 +1229,6 @@ public class GeckoAppShell
|
||||
return intent;
|
||||
}
|
||||
|
||||
/* On some devices, access to the clipboard service needs to happen
|
||||
* on a thread with a looper, so this function requires a looper is
|
||||
* present on the thread. */
|
||||
private static String getClipboardTextImpl() {
|
||||
Context context = getContext();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
android.content.ClipboardManager cm = (android.content.ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm.hasPrimaryClip()) {
|
||||
ClipData clip = cm.getPrimaryClip();
|
||||
if (clip != null) {
|
||||
ClipData.Item item = clip.getItemAt(0);
|
||||
return item.coerceToText(context).toString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
android.text.ClipboardManager cm = (android.text.ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm.hasText()) {
|
||||
return cm.getText().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SynchronousQueue<String> sClipboardQueue = new SynchronousQueue<String>();
|
||||
|
||||
static String getClipboardText() {
|
||||
// If we're on the UI thread or the background thread, we have a looper on the thread
|
||||
// and can just call this directly. For any other threads, post the call to the
|
||||
// background thread.
|
||||
|
||||
if (ThreadUtils.isOnUiThread() || ThreadUtils.isOnBackgroundThread()) {
|
||||
return getClipboardTextImpl();
|
||||
}
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String text = getClipboardTextImpl();
|
||||
try {
|
||||
sClipboardQueue.put(text != null ? text : "");
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
});
|
||||
try {
|
||||
return sClipboardQueue.take();
|
||||
} catch (InterruptedException ie) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static void setClipboardText(String copiedText) {
|
||||
// Copy an empty string instead of null to avoid clipboard crashes.
|
||||
// AndroidBridge::EmptyClipboard() passes null to clear the clipboard's current contents.
|
||||
final String text = (copiedText != null) ? copiedText : "";
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Context context = getContext();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
android.content.ClipboardManager cm = (android.content.ClipboardManager)
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("Text", text);
|
||||
try {
|
||||
cm.setPrimaryClip(clip);
|
||||
} catch (NullPointerException e) {
|
||||
// Bug 776223: This is a Samsung clipboard bug. setPrimaryClip() can throw
|
||||
// a NullPointerException if Samsung's /data/clipboard directory is full.
|
||||
// Fortunately, the text is still successfully copied to the clipboard.
|
||||
}
|
||||
} else {
|
||||
android.text.ClipboardManager cm = (android.text.ClipboardManager)
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setText(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setNotificationClient(NotificationClient client) {
|
||||
if (sNotificationClient == null) {
|
||||
sNotificationClient = client;
|
||||
|
@ -7,6 +7,7 @@ package org.mozilla.gecko;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
@ -79,6 +80,7 @@ public class GeckoApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
HardwareUtils.init(getApplicationContext());
|
||||
Clipboard.init(getApplicationContext());
|
||||
GeckoLoader.loadMozGlue(getApplicationContext());
|
||||
super.onCreate();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.gfx.InputConnectionHandler;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.GamepadUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
@ -271,10 +272,10 @@ class GeckoInputConnection
|
||||
// If selection is empty, we'll select everything
|
||||
if (selStart == selEnd) {
|
||||
// Fill the clipboard
|
||||
GeckoAppShell.setClipboardText(editable.toString());
|
||||
Clipboard.setText(editable);
|
||||
editable.clear();
|
||||
} else {
|
||||
GeckoAppShell.setClipboardText(
|
||||
Clipboard.setText(
|
||||
editable.toString().substring(
|
||||
Math.min(selStart, selEnd),
|
||||
Math.max(selStart, selEnd)));
|
||||
@ -282,7 +283,7 @@ class GeckoInputConnection
|
||||
}
|
||||
break;
|
||||
case R.id.paste:
|
||||
commitText(GeckoAppShell.getClipboardText(), 1);
|
||||
commitText(Clipboard.getText(), 1);
|
||||
break;
|
||||
case R.id.copy:
|
||||
// Copy the current selection or the empty string if nothing is selected.
|
||||
@ -290,7 +291,7 @@ class GeckoInputConnection
|
||||
editable.toString().substring(
|
||||
Math.min(selStart, selEnd),
|
||||
Math.max(selStart, selEnd));
|
||||
GeckoAppShell.setClipboardText(copiedText);
|
||||
Clipboard.setText(copiedText);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
@ -27,6 +27,7 @@ MOZGLUE_PP_JAVA_FILES := \
|
||||
UTIL_JAVA_FILES := \
|
||||
util/ActivityResultHandler.java \
|
||||
util/ActivityResultHandlerMap.java \
|
||||
util/Clipboard.java \
|
||||
util/EventDispatcher.java \
|
||||
util/FloatUtils.java \
|
||||
util/GamepadUtils.java \
|
||||
|
110
mobile/android/base/util/Clipboard.java
Normal file
110
mobile/android/base/util/Clipboard.java
Normal file
@ -0,0 +1,110 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.util;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
public final class Clipboard {
|
||||
private static Context mContext;
|
||||
private final static String LOG_TAG = "Clipboard";
|
||||
private final static SynchronousQueue<String> sClipboardQueue = new SynchronousQueue<String>();
|
||||
|
||||
private Clipboard() {
|
||||
}
|
||||
|
||||
public static void init(Context c) {
|
||||
if (mContext != null) {
|
||||
Log.w(LOG_TAG, "Clipboard.init() called twice!");
|
||||
return;
|
||||
}
|
||||
mContext = c;
|
||||
}
|
||||
|
||||
public static String getText() {
|
||||
// If we're on the UI thread or the background thread, we have a looper on the thread
|
||||
// and can just call this directly. For any other threads, post the call to the
|
||||
// background thread.
|
||||
|
||||
if (ThreadUtils.isOnUiThread() || ThreadUtils.isOnBackgroundThread()) {
|
||||
return getClipboardTextImpl();
|
||||
}
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String text = getClipboardTextImpl();
|
||||
try {
|
||||
sClipboardQueue.put(text != null ? text : "");
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
});
|
||||
try {
|
||||
return sClipboardQueue.take();
|
||||
} catch (InterruptedException ie) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void setText(final CharSequence text) {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void run() {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
android.content.ClipboardManager cm = getClipboardManager11(mContext);
|
||||
ClipData clip = ClipData.newPlainText("Text", text);
|
||||
try {
|
||||
cm.setPrimaryClip(clip);
|
||||
} catch (NullPointerException e) {
|
||||
// Bug 776223: This is a Samsung clipboard bug. setPrimaryClip() can throw
|
||||
// a NullPointerException if Samsung's /data/clipboard directory is full.
|
||||
// Fortunately, the text is still successfully copied to the clipboard.
|
||||
}
|
||||
} else {
|
||||
android.text.ClipboardManager cm = getClipboardManager(mContext);
|
||||
cm.setText(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static android.content.ClipboardManager getClipboardManager11(Context context) {
|
||||
// In API Level 11 and above, CLIPBOARD_SERVICE returns android.content.ClipboardManager,
|
||||
// which is a subclass of android.text.ClipboardManager.
|
||||
return (android.content.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
}
|
||||
|
||||
private static android.text.ClipboardManager getClipboardManager(Context context) {
|
||||
return (android.text.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
}
|
||||
|
||||
/* On some devices, access to the clipboard service needs to happen
|
||||
* on a thread with a looper, so this function requires a looper is
|
||||
* present on the thread. */
|
||||
@SuppressWarnings("deprecation")
|
||||
private static String getClipboardTextImpl() {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
android.content.ClipboardManager cm = getClipboardManager11(mContext);
|
||||
if (cm.hasPrimaryClip()) {
|
||||
ClipData clip = cm.getPrimaryClip();
|
||||
if (clip != null) {
|
||||
ClipData.Item item = clip.getItemAt(0);
|
||||
return item.coerceToText(mContext).toString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
android.text.ClipboardManager cm = getClipboardManager(mContext);
|
||||
if (cm.hasText()) {
|
||||
return cm.getText().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -123,8 +123,6 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
||||
jGetMimeTypeFromExtensions = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jGetExtensionFromMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V");
|
||||
jGetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getClipboardText", "()Ljava/lang/String;");
|
||||
jSetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setClipboardText", "(Ljava/lang/String;)V");
|
||||
jShowAlertNotification = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
jShowFilePickerForExtensions = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerForExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jShowFilePickerForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerForMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
@ -242,6 +240,10 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
||||
|
||||
jGetContext = (jmethodID)jEnv->GetStaticMethodID(jGeckoAppShellClass, "getContext", "()Landroid/content/Context;");
|
||||
|
||||
jClipboardClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/util/Clipboard"));
|
||||
jClipboardGetText = (jmethodID) jEnv->GetStaticMethodID(jClipboardClass, "getText", "()Ljava/lang/String;");
|
||||
jClipboardSetText = (jmethodID) jEnv->GetStaticMethodID(jClipboardClass, "setText", "(Ljava/lang/CharSequence;)V");
|
||||
|
||||
InitAndroidJavaWrappers(jEnv);
|
||||
|
||||
// jEnv should NOT be cached here by anything -- the jEnv here
|
||||
@ -632,8 +634,8 @@ AndroidBridge::GetClipboardText(nsAString& aText)
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
jstring jstrType = static_cast<jstring>(
|
||||
env->CallStaticObjectMethod(mGeckoAppShellClass,
|
||||
jGetClipboardText));
|
||||
env->CallStaticObjectMethod(jClipboardClass,
|
||||
jClipboardGetText));
|
||||
if (jniFrame.CheckForException() || !jstrType)
|
||||
return false;
|
||||
|
||||
@ -653,7 +655,7 @@ AndroidBridge::SetClipboardText(const nsAString& aText)
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
jstring jstr = NewJavaString(&jniFrame, aText);
|
||||
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, jstr);
|
||||
env->CallStaticVoidMethod(jClipboardClass, jClipboardSetText, jstr);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -667,8 +669,8 @@ AndroidBridge::ClipboardHasText()
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
jstring jstrType = static_cast<jstring>(
|
||||
env->CallStaticObjectMethod(mGeckoAppShellClass,
|
||||
jGetClipboardText));
|
||||
env->CallStaticObjectMethod(jClipboardClass,
|
||||
jClipboardGetText));
|
||||
if (jniFrame.CheckForException() || !jstrType)
|
||||
return false;
|
||||
|
||||
@ -685,7 +687,7 @@ AndroidBridge::EmptyClipboard()
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env, 0);
|
||||
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, nullptr);
|
||||
env->CallStaticVoidMethod(jClipboardClass, jClipboardSetText, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -473,8 +473,6 @@ protected:
|
||||
jmethodID jGetMimeTypeFromExtensions;
|
||||
jmethodID jGetExtensionFromMimeType;
|
||||
jmethodID jMoveTaskToBack;
|
||||
jmethodID jGetClipboardText;
|
||||
jmethodID jSetClipboardText;
|
||||
jmethodID jShowAlertNotification;
|
||||
jmethodID jShowFilePickerForExtensions;
|
||||
jmethodID jShowFilePickerForMimeType;
|
||||
@ -562,6 +560,10 @@ protected:
|
||||
jmethodID jRequestContentRepaint;
|
||||
jmethodID jPostDelayedCallback;
|
||||
|
||||
jclass jClipboardClass;
|
||||
jmethodID jClipboardGetText;
|
||||
jmethodID jClipboardSetText;
|
||||
|
||||
// some convinient types to have around
|
||||
jclass jStringClass;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user