[go: nahoru, domu]

[TextField Selection] Adjust the Toolbar Menu.

- When ClipboardManager is empty, don't show paste.
- When Selection collapses, don't show copy and cut.

Bug:160819163
Test: Manuall tested.
Test: ./gradlew :compose:foundation:foundation-text:testDebugUnitTest
Test: ./gradlew :compose:core:core:testDebugUnitTest

RelNote: Ajdust the Toolbar Menu to show copy, cut, paste properly.
Change-Id: Id3955ab3845cc6ad1807b95bc39e73facf0fd358
diff --git a/ui/ui-core/api/0.1.0-dev15.txt b/ui/ui-core/api/0.1.0-dev15.txt
index a90510a..f50330a 100644
--- a/ui/ui-core/api/0.1.0-dev15.txt
+++ b/ui/ui-core/api/0.1.0-dev15.txt
@@ -1989,11 +1989,13 @@
   public interface TextToolbar {
     method public androidx.ui.core.texttoolbar.TextToolbarStatus getStatus();
     method public void hide();
-    method public void showCopyMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onDeselectRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested);
-    method public void showPasteMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onPasteRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCutRequested);
+    method public void showMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>? >
     property public abstract androidx.ui.core.texttoolbar.TextToolbarStatus status;
   }
 
+  public final class TextToolbarKt {
+  }
+
   public enum TextToolbarStatus {
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus valueOf(String name) throws java.lang.IllegalArgumentException;
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus[] values();
diff --git a/ui/ui-core/api/current.txt b/ui/ui-core/api/current.txt
index a90510a..f50330a 100644
--- a/ui/ui-core/api/current.txt
+++ b/ui/ui-core/api/current.txt
@@ -1989,11 +1989,13 @@
   public interface TextToolbar {
     method public androidx.ui.core.texttoolbar.TextToolbarStatus getStatus();
     method public void hide();
-    method public void showCopyMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onDeselectRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested);
-    method public void showPasteMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onPasteRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCutRequested);
+    method public void showMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>? >
     property public abstract androidx.ui.core.texttoolbar.TextToolbarStatus status;
   }
 
+  public final class TextToolbarKt {
+  }
+
   public enum TextToolbarStatus {
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus valueOf(String name) throws java.lang.IllegalArgumentException;
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus[] values();
diff --git a/ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt b/ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt
index a90510a..f50330a 100644
--- a/ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt
+++ b/ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt
@@ -1989,11 +1989,13 @@
   public interface TextToolbar {
     method public androidx.ui.core.texttoolbar.TextToolbarStatus getStatus();
     method public void hide();
-    method public void showCopyMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onDeselectRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested);
-    method public void showPasteMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onPasteRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCutRequested);
+    method public void showMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>? >
     property public abstract androidx.ui.core.texttoolbar.TextToolbarStatus status;
   }
 
+  public final class TextToolbarKt {
+  }
+
   public enum TextToolbarStatus {
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus valueOf(String name) throws java.lang.IllegalArgumentException;
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus[] values();
diff --git a/ui/ui-core/api/public_plus_experimental_current.txt b/ui/ui-core/api/public_plus_experimental_current.txt
index a90510a..f50330a 100644
--- a/ui/ui-core/api/public_plus_experimental_current.txt
+++ b/ui/ui-core/api/public_plus_experimental_current.txt
@@ -1989,11 +1989,13 @@
   public interface TextToolbar {
     method public androidx.ui.core.texttoolbar.TextToolbarStatus getStatus();
     method public void hide();
-    method public void showCopyMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onDeselectRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested);
-    method public void showPasteMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onPasteRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCutRequested);
+    method public void showMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>? >
     property public abstract androidx.ui.core.texttoolbar.TextToolbarStatus status;
   }
 
+  public final class TextToolbarKt {
+  }
+
   public enum TextToolbarStatus {
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus valueOf(String name) throws java.lang.IllegalArgumentException;
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus[] values();
diff --git a/ui/ui-core/api/restricted_0.1.0-dev15.txt b/ui/ui-core/api/restricted_0.1.0-dev15.txt
index afa5b10..26d10d1 100644
--- a/ui/ui-core/api/restricted_0.1.0-dev15.txt
+++ b/ui/ui-core/api/restricted_0.1.0-dev15.txt
@@ -2041,11 +2041,13 @@
   public interface TextToolbar {
     method public androidx.ui.core.texttoolbar.TextToolbarStatus getStatus();
     method public void hide();
-    method public void showCopyMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onDeselectRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested);
-    method public void showPasteMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onPasteRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCutRequested);
+    method public void showMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>? >
     property public abstract androidx.ui.core.texttoolbar.TextToolbarStatus status;
   }
 
+  public final class TextToolbarKt {
+  }
+
   public enum TextToolbarStatus {
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus valueOf(String name) throws java.lang.IllegalArgumentException;
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus[] values();
diff --git a/ui/ui-core/api/restricted_current.txt b/ui/ui-core/api/restricted_current.txt
index afa5b10..26d10d1 100644
--- a/ui/ui-core/api/restricted_current.txt
+++ b/ui/ui-core/api/restricted_current.txt
@@ -2041,11 +2041,13 @@
   public interface TextToolbar {
     method public androidx.ui.core.texttoolbar.TextToolbarStatus getStatus();
     method public void hide();
-    method public void showCopyMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onDeselectRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested);
-    method public void showPasteMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit> onCopyRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onPasteRequested, kotlin.jvm.functions.Function0<kotlin.Unit> onCutRequested);
+    method public void showMenu(androidx.ui.geometry.Rect rect, kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>?  kotlin.jvm.functions.Function0<kotlin.Unit>? >
     property public abstract androidx.ui.core.texttoolbar.TextToolbarStatus status;
   }
 
+  public final class TextToolbarKt {
+  }
+
   public enum TextToolbarStatus {
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus valueOf(String name) throws java.lang.IllegalArgumentException;
     method public static androidx.ui.core.texttoolbar.TextToolbarStatus[] values();
diff --git a/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/AndroidTextToolbar.kt b/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/AndroidTextToolbar.kt
index c938d00..6aa6c1a 100644
--- a/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/AndroidTextToolbar.kt
+++ b/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/AndroidTextToolbar.kt
@@ -22,7 +22,6 @@
 import androidx.ui.core.texttoolbar.actionmodecallback.FloatingTextActionModeCallback
 import androidx.ui.core.texttoolbar.actionmodecallback.PrimaryTextActionModeCallback
 import androidx.ui.core.texttoolbar.actionmodecallback.TextActionModeCallback
-import androidx.ui.core.texttoolbar.actionmodecallback.TextFieldActionModeCallback
 import androidx.ui.geometry.Rect
 
 /**
@@ -32,10 +31,11 @@
     private var actionMode: ActionMode? = null
     private var textToolbarStatus = TextToolbarStatus.Hidden
 
-    override fun showCopyMenu(
+    override fun showMenu(
         rect: Rect,
-        onDeselectRequested: () -> Unit,
-        onCopyRequested: () -> Unit
+        onCopyRequested: ActionCallback?,
+        onPasteRequested: ActionCallback?,
+        onCutRequested: ActionCallback?
     ) {
         textToolbarStatus = TextToolbarStatus.Shown
         if (Build.VERSION.SDK_INT >= 23) {
@@ -44,40 +44,6 @@
                     TextActionModeCallback(
                         view = view,
                         >
-                        >
-                    )
-                )
-            actionModeCallback.setRect(rect)
-            actionMode = view.startActionMode(
-                actionModeCallback,
-                ActionMode.TYPE_FLOATING
-            )
-        } else {
-            val actionModeCallback =
-                PrimaryTextActionModeCallback(
-                    TextActionModeCallback(
-                        view = view,
-                        >
-                        >
-                    )
-                )
-            actionMode = view.startActionMode(actionModeCallback)
-        }
-    }
-
-    override fun showPasteMenu(
-        rect: Rect,
-        onCopyRequested: () -> Unit,
-        onPasteRequested: () -> Unit,
-        onCutRequested: () -> Unit
-    ) {
-        textToolbarStatus = TextToolbarStatus.Shown
-        if (Build.VERSION.SDK_INT >= 23) {
-            val actionModeCallback =
-                FloatingTextActionModeCallback(
-                    TextFieldActionModeCallback(
-                        view = view,
-                        >
                         >
                         >
                     )
@@ -90,7 +56,7 @@
         } else {
             val actionModeCallback =
                 PrimaryTextActionModeCallback(
-                    TextFieldActionModeCallback(
+                    TextActionModeCallback(
                         view = view,
                         >
                         >
diff --git a/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextActionModeCallback.kt b/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextActionModeCallback.kt
index c0cf08d..bf40806 100644
--- a/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextActionModeCallback.kt
+++ b/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextActionModeCallback.kt
@@ -20,6 +20,7 @@
 import android.view.Menu
 import android.view.MenuItem
 import android.view.View
+import androidx.ui.core.texttoolbar.ActionCallback
 
 internal const val MENU_ITEM_COPY = 0
 internal const val MENU_ITEM_PASTE = 1
@@ -27,15 +28,28 @@
 
 internal class TextActionModeCallback(
     private val view: View,
-    private val onDeselectRequested: () -> Unit,
-    private val onCopyRequested: () -> Unit
+    private val onCopyRequested: ActionCallback? = null,
+    private val onPasteRequested: ActionCallback? = null,
+    private val onCutRequested: ActionCallback? = null
 ) : ActionMode.Callback {
     override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
         requireNotNull(menu)
         requireNotNull(mode)
 
-        menu.add(0, MENU_ITEM_COPY, 0, android.R.string.copy)
-            .setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW)
+        onCopyRequested?.let {
+            menu.add(0, MENU_ITEM_COPY, 0, android.R.string.copy)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
+        }
+
+        onPasteRequested?.let {
+            menu.add(0, MENU_ITEM_PASTE, 1, android.R.string.paste)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
+        }
+
+        onCutRequested?.let {
+            menu.add(0, MENU_ITEM_CUT, 2, android.R.string.cut)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
+        }
         return true
     }
 
@@ -44,14 +58,15 @@
     }
 
     override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
-        if (item!!.itemId == MENU_ITEM_COPY) {
-            onCopyRequested()
-            onDeselectRequested()
-            mode?.finish()
-            return true
+        when (item!!.itemId) {
+            MENU_ITEM_COPY -> onCopyRequested?.invoke()
+            MENU_ITEM_PASTE -> onPasteRequested?.invoke()
+            MENU_ITEM_CUT -> onCutRequested?.invoke()
+            else -> return false
         }
-        return false
+        mode?.finish()
+        return true
     }
 
     override fun onDestroyActionMode(mode: ActionMode?) {}
-}
\ No newline at end of file
+}
diff --git a/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextFieldActionModeCallback.kt b/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextFieldActionModeCallback.kt
deleted file mode 100644
index 21352b4..0000000
--- a/ui/ui-core/src/androidMain/kotlin/androidx/ui/core/texttoolbar/actionmodecallback/TextFieldActionModeCallback.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.ui.core.texttoolbar.actionmodecallback
-
-import android.view.ActionMode
-import android.view.Menu
-import android.view.MenuItem
-import android.view.View
-
-internal class TextFieldActionModeCallback(
-    private val view: View,
-    private val onCopyRequested: () -> Unit,
-    private val onPasteRequested: () -> Unit,
-    private val onCutRequested: () -> Unit
-) : ActionMode.Callback {
-    override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
-        requireNotNull(menu)
-        requireNotNull(mode)
-
-        menu.add(0, MENU_ITEM_COPY, 0, android.R.string.copy)
-            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
-        menu.add(0, MENU_ITEM_PASTE, 1, android.R.string.paste)
-            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
-        menu.add(0, MENU_ITEM_CUT, 2, android.R.string.cut)
-            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
-        return true
-    }
-
-    override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
-        return false
-    }
-
-    override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
-        when (item!!.itemId) {
-            MENU_ITEM_COPY -> onCopyRequested()
-            MENU_ITEM_PASTE -> onPasteRequested()
-            MENU_ITEM_CUT -> onCutRequested()
-            else -> return false
-        }
-        mode?.finish()
-        return true
-    }
-
-    override fun onDestroyActionMode(mode: ActionMode?) {}
-}
diff --git a/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/selection/SelectionManager.kt b/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/selection/SelectionManager.kt
index 93c3967..51f5a9e 100644
--- a/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/selection/SelectionManager.kt
+++ b/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/selection/SelectionManager.kt
@@ -255,10 +255,12 @@
      */
     internal fun showSelectionToolbar() {
         selection?.let {
-            textToolbar?.showCopyMenu(
+            textToolbar?.showMenu(
                 getContentRect(),
-                 copy() },
-                 onRelease() }
+                >
+                    copy()
+                    onRelease()
+                }
             )
         }
     }
diff --git a/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/texttoolbar/TextToolbar.kt b/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/texttoolbar/TextToolbar.kt
index c919018..aefab92 100644
--- a/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/texttoolbar/TextToolbar.kt
+++ b/ui/ui-core/src/commonMain/kotlin/androidx/ui/core/texttoolbar/TextToolbar.kt
@@ -18,25 +18,12 @@
 
 import androidx.ui.geometry.Rect
 
+internal typealias ActionCallback = () -> Unit
 /**
  * Interface for text-related toolbar.
  */
 interface TextToolbar {
     /**
-     * Show the floating toolbar(post-M) or primary toolbar(pre-M) for copying text.
-     *
-     * @param rect region of interest. The selected region around which the floating toolbar
-     * should show.
-     * @param onDeselectRequested callback to deselect after the floating toolbar is clicked.
-     * @param onCopyRequested callback to copy text into ClipBoardManager.
-     */
-    fun showCopyMenu(
-        rect: Rect,
-        onDeselectRequested: () -> Unit,
-        onCopyRequested: () -> Unit
-    )
-
-    /**
      * Show the floating toolbar(post-M) or primary toolbar(pre-M) for copying, cutting and pasting
      * text.
      * @param rect region of interest. The selected region around which the floating toolbar
@@ -45,11 +32,11 @@
      * @param onPasteRequested callback to get text from ClipBoardManager and paste it.
      * @param onCutRequested callback to cut text and copy the text into ClipBoardManager.
      */
-    fun showPasteMenu(
+    fun showMenu(
         rect: Rect,
-        onCopyRequested: () -> Unit,
-        onPasteRequested: () -> Unit,
-        onCutRequested: () -> Unit
+        onCopyRequested: ActionCallback? = null,
+        onPasteRequested: ActionCallback? = null,
+        onCutRequested: ActionCallback? = null
     )
 
     /**
diff --git a/ui/ui-core/src/test/kotlin/androidx/ui/core/selection/SelectionManagerTest.kt b/ui/ui-core/src/test/kotlin/androidx/ui/core/selection/SelectionManagerTest.kt
index 0fa11b2..f5a33f9 100644
--- a/ui/ui-core/src/test/kotlin/androidx/ui/core/selection/SelectionManagerTest.kt
+++ b/ui/ui-core/src/test/kotlin/androidx/ui/core/selection/SelectionManagerTest.kt
@@ -32,6 +32,7 @@
 import com.nhaarman.mockitokotlin2.any
 import com.nhaarman.mockitokotlin2.doReturn
 import com.nhaarman.mockitokotlin2.eq
+import com.nhaarman.mockitokotlin2.isNull
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.spy
 import com.nhaarman.mockitokotlin2.times
@@ -354,7 +355,7 @@
     }
 
     @Test
-    fun showSelectionToolbar_trigger_textToolbar_showCopyMenu() {
+    fun showSelectionToolbar_trigger_textToolbar_showMenu() {
         val text = "Text Demo"
         val annotatedString = AnnotatedString(text = text)
         val startOffset = text.indexOf('m')
@@ -375,10 +376,11 @@
 
         selectionManager.showSelectionToolbar()
 
-        verify(textToolbar, times(1)).showCopyMenu(
+        verify(textToolbar, times(1)).showMenu(
             eq(Rect.zero),
             any(),
-            any()
+            isNull(),
+            isNull()
         )
     }
 
diff --git a/ui/ui-text/src/commonMain/kotlin/androidx/ui/text/selection/TextFieldSelectionManager.kt b/ui/ui-text/src/commonMain/kotlin/androidx/ui/text/selection/TextFieldSelectionManager.kt
index 85763f4..d72c050 100644
--- a/ui/ui-text/src/commonMain/kotlin/androidx/ui/text/selection/TextFieldSelectionManager.kt
+++ b/ui/ui-text/src/commonMain/kotlin/androidx/ui/text/selection/TextFieldSelectionManager.kt
@@ -290,23 +290,33 @@
      * the copy, paste and cut method as callbacks when "copy", "cut" or "paste" is clicked.
      */
     internal fun showSelectionToolbar() {
-        if (!value.selection.collapsed) {
-            textToolbar?.showPasteMenu(
-                rect = getContentRect(),
-                >
-                    copy()
-                    hideSelectionToolbar()
-                },
-                >
-                    paste()
-                    hideSelectionToolbar()
-                },
-                >
-                    cut()
-                    hideSelectionToolbar()
-                }
-            )
-        }
+        val copy: (() -> Unit)? = if (!value.selection.collapsed) {
+            {
+                copy()
+                hideSelectionToolbar()
+            }
+        } else null
+
+        val cut: (() -> Unit)? = if (!value.selection.collapsed) {
+            {
+                cut()
+                hideSelectionToolbar()
+            }
+        } else null
+
+        val paste: (() -> Unit)? = if (clipboardManager?.getText() != null) {
+            {
+                paste()
+                hideSelectionToolbar()
+            }
+        } else null
+
+        textToolbar?.showMenu(
+            rect = getContentRect(),
+            >
+            >
+            >
+        )
     }
 
     private fun hideSelectionToolbar() {
diff --git a/ui/ui-text/src/test/kotlin/androidx/ui/text/selection/TextFieldSelectionManagerTest.kt b/ui/ui-text/src/test/kotlin/androidx/ui/text/selection/TextFieldSelectionManagerTest.kt
index 3a226e0..892f521 100644
--- a/ui/ui-text/src/test/kotlin/androidx/ui/text/selection/TextFieldSelectionManagerTest.kt
+++ b/ui/ui-text/src/test/kotlin/androidx/ui/text/selection/TextFieldSelectionManagerTest.kt
@@ -37,6 +37,7 @@
 import androidx.ui.unit.Density
 import com.google.common.truth.Truth.assertThat
 import com.nhaarman.mockitokotlin2.any
+import com.nhaarman.mockitokotlin2.isNull
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.spy
 import com.nhaarman.mockitokotlin2.times
@@ -283,7 +284,7 @@
     }
 
     @Test
-    fun showSelectionToolbar_trigger_textToolbar_showPasteMenu() {
+    fun showSelectionToolbar_trigger_textToolbar_showMenu_Clipboard_empty_not_show_paste() {
         manager.value = TextFieldValue(
             text = text + text,
             selection = TextRange("Hello".length, text.length)
@@ -291,6 +292,19 @@
 
         manager.showSelectionToolbar()
 
-        verify(textToolbar, times(1)).showPasteMenu(any(), any(), any(), any())
+        verify(textToolbar, times(1)).showMenu(any(), any(), isNull(), any())
+    }
+
+    @Test
+    fun showSelectionToolbar_trigger_textToolbar_showMenu_selection_collapse_not_show_copy_cut() {
+        whenever(clipboardManager.getText()).thenReturn(AnnotatedString(text))
+        manager.value = TextFieldValue(
+            text = text + text,
+            selection = TextRange(0, 0)
+        )
+
+        manager.showSelectionToolbar()
+
+        verify(textToolbar, times(1)).showMenu(any(), isNull(), any(), isNull())
     }
 }