Bug 1463576 - 7. Simplify clipboard code; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Fri, 01 Jun 2018 13:39:21 -0400
changeset 802944 51f0c9a68dd7e7cc2fd29a8ac8ccdef4604a747b
parent 802943 477ceef33a03c8788e7423bd8217cb715efe98b6
child 802945 89ccfe50f136e337345a01f52e8af92475ddd9c2
push id112001
push userbmo:nchen@mozilla.com
push dateFri, 01 Jun 2018 17:40:20 +0000
reviewerssnorp
bugs1463576
milestone62.0a1
Bug 1463576 - 7. Simplify clipboard code; r?snorp Don't use a different thread when accessing the clipboard. The original issue was using the clipboard required a thread with a Looper, when GeckoThread did not have one. It does have one now so it's safe to access the clipboard there. Also, make hasText() return false for empty strings to avoid us mistakenly think there is something on the clipboard. MozReview-Commit-ID: AwKEcNnIkhT
mobile/android/geckoview/src/main/java/org/mozilla/gecko/Clipboard.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/Clipboard.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/Clipboard.java
@@ -7,101 +7,61 @@ package org.mozilla.gecko;
 import java.util.concurrent.SynchronousQueue;
 
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.ClipboardManager;
 import android.content.ClipData;
 import android.content.Context;
-import android.util.Log;
+import android.text.TextUtils;
 
 public final class Clipboard {
     private final static String LOGTAG = "GeckoClipboard";
-    private final static SynchronousQueue<String> sClipboardQueue = new SynchronousQueue<String>();
 
     private Clipboard() {
     }
 
     @WrapForJNI(calledFrom = "gecko")
     public static String getText(final Context context) {
-        // 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(context);
+        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();
+            }
         }
-
-        ThreadUtils.postToBackgroundThread(new Runnable() {
-            @Override
-            public void run() {
-                String text = getClipboardTextImpl(context);
-                try {
-                    sClipboardQueue.put(text != null ? text : "");
-                } catch (InterruptedException ie) { }
-            }
-        });
-
-        try {
-            return sClipboardQueue.take();
-        } catch (InterruptedException ie) {
-            return "";
-        }
+        return null;
     }
 
     @WrapForJNI(calledFrom = "gecko")
     public static void setText(final Context context, final CharSequence text) {
-        ThreadUtils.postToBackgroundThread(new Runnable() {
-            @Override
-            public void run() {
-                // 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);
-                final 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.
-                }
-                return;
-            }
-        });
+        // 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));
+        } 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.
+        }
     }
 
     /**
      * @return true if the clipboard is nonempty, false otherwise.
      */
     @WrapForJNI(calledFrom = "gecko")
     public static boolean hasText(final Context context) {
-        final ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
-        return cm.hasPrimaryClip();
+        return !TextUtils.isEmpty(getText(context));
     }
 
     /**
      * Deletes all text from the clipboard.
      */
     @WrapForJNI(calledFrom = "gecko")
     public static void clearText(final Context context) {
         setText(context, null);
     }
-
-    /**
-     * 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")
-    static String getClipboardTextImpl(final Context context) {
-        final ClipboardManager cm = (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();
-            }
-        }
-        return null;
-    }
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
@@ -116,16 +116,19 @@ public final class GeckoRuntime implemen
 
         mSettings = settings;
 
         // Bug 1453062 -- the EventDispatcher should really live here (or in GeckoThread)
         EventDispatcher.getInstance().registerUiThreadListener(mEventListener, "Gecko:Exited");
 
         mSettings.runtime = this;
         mSettings.flush();
+
+        // Initialize the system ClipboardManager by accessing it on the main thread.
+        GeckoAppShell.getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE);
         return true;
     }
 
     /**
      * Create a new runtime with default settings and attach it to the given
      * context.
      *
      * Create will throw if there is already an active Gecko instance running,