summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/widget/TextView.java104
-rw-r--r--core/res/res/layout/text_drag_thumbnail.xml26
2 files changed, 121 insertions, 9 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3838a02d1caa..acefe5db2153 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -23,6 +23,7 @@ import org.xmlpull.v1.XmlPullParserException;
import android.R;
import android.content.ClipData;
+import android.content.ClipData.Item;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -88,6 +89,7 @@ import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextMenu;
+import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -6731,10 +6733,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mMovement.onTakeFocus(this, (Spannable) mText, direction);
}
- if (mSelectAllOnFocus) {
- Selection.setSelection((Spannable) mText, 0, mText.length());
- }
-
// The DecorView does not have focus when the 'Done' ExtractEditText button is
// pressed. Since it is the ViewRoot's mView, it requests focus before
// ExtractEditText clears focus, which gives focus to the ExtractEditText.
@@ -6753,6 +6751,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
Selection.setSelection((Spannable) mText, selStart, selEnd);
}
+
+ if (mSelectAllOnFocus) {
+ Selection.setSelection((Spannable) mText, 0, mText.length());
+ }
+
mTouchFocusSelected = true;
}
@@ -7029,12 +7032,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|| windowParams.type > WindowManager.LayoutParams.LAST_SUB_WINDOW;
}
- // TODO Add an extra android:cursorController flag to disable the controller?
- if (windowSupportsHandles && mCursorVisible && mLayout != null) {
+ if (windowSupportsHandles && isTextEditable() && mCursorVisible && mLayout != null) {
if (mInsertionPointCursorController == null) {
mInsertionPointCursorController = new InsertionPointCursorController();
}
} else {
+ hideInsertionPointCursorController();
mInsertionPointCursorController = null;
}
@@ -7044,7 +7047,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
} else {
// Stop selection mode if the controller becomes unavailable.
- stopSelectionActionMode();
+ if (mSelectionModifierCursorController != null) {
+ stopSelectionActionMode();
+ }
mSelectionModifierCursorController = null;
}
}
@@ -7053,7 +7058,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @return True iff this TextView contains a text that can be edited.
*/
private boolean isTextEditable() {
- return mText instanceof Editable && onCheckIsTextEditor();
+ return mText instanceof Editable && onCheckIsTextEditor() && isEnabled();
}
/**
@@ -7684,13 +7689,53 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return packRangeInLong(min, max);
}
+ private DragThumbnailBuilder getTextThumbnailBuilder(CharSequence text) {
+ TextView thumbnail = (TextView) inflate(mContext,
+ com.android.internal.R.layout.text_drag_thumbnail, null);
+
+ if (thumbnail == null) {
+ throw new IllegalArgumentException("Unable to inflate text drag thumbnail");
+ }
+
+ if (text.length() > DRAG_THUMBNAIL_MAX_TEXT_LENGTH) {
+ text = text.subSequence(0, DRAG_THUMBNAIL_MAX_TEXT_LENGTH);
+ }
+ thumbnail.setText(text);
+ thumbnail.setTextColor(getTextColors());
+
+ thumbnail.setTextAppearance(mContext, R.styleable.Theme_textAppearanceLarge);
+ thumbnail.setGravity(Gravity.CENTER);
+
+ thumbnail.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ thumbnail.measure(size, size);
+
+ thumbnail.layout(0, 0, thumbnail.getMeasuredWidth(), thumbnail.getMeasuredHeight());
+ thumbnail.invalidate();
+ return new DragThumbnailBuilder(thumbnail);
+ }
+
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
mEatTouchRelease = true;
return true;
}
-
+
+ if (mSelectionActionMode != null && touchPositionIsInSelection()) {
+ final int start = getSelectionStart();
+ final int end = getSelectionEnd();
+ CharSequence selectedText = mTransformed.subSequence(start, end);
+ ClipData data = ClipData.newPlainText(null, null, selectedText);
+ startDrag(data, getTextThumbnailBuilder(selectedText), false);
+ stopSelectionActionMode();
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ mEatTouchRelease = true;
+ return true;
+ }
+
if (startSelectionActionMode()) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mEatTouchRelease = true;
@@ -8728,6 +8773,46 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return getOffsetForHorizontal(line, x);
}
+ @Override
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED:
+ return mInsertionPointCursorController != null;
+
+ case DragEvent.ACTION_DRAG_ENTERED:
+ TextView.this.requestFocus();
+ return true;
+
+ case DragEvent.ACTION_DRAG_LOCATION: {
+ final int offset = getOffset((int)event.getX(), (int)event.getY());
+ Selection.setSelection((Spannable)mText, offset);
+ return true;
+ }
+
+ case DragEvent.ACTION_DROP: {
+ StringBuilder content = new StringBuilder("");
+ ClipData clipData = event.getClipData();
+ final int itemCount = clipData.getItemCount();
+ for (int i=0; i < itemCount; i++) {
+ Item item = clipData.getItem(i);
+ content.append(item.coerceToText(TextView.this.mContext));
+ }
+ final int offset = getOffset((int) event.getX(), (int) event.getY());
+ long minMax = prepareSpacesAroundPaste(offset, offset, content);
+ int min = extractRangeStartFromLong(minMax);
+ int max = extractRangeEndFromLong(minMax);
+ Selection.setSelection((Spannable) mText, max);
+ ((Editable) mText).replace(min, max, content);
+ return true;
+ }
+
+ case DragEvent.ACTION_DRAG_EXITED:
+ case DragEvent.ACTION_DRAG_ENDED:
+ default:
+ return true;
+ }
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
@@ -8822,4 +8907,5 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
private InputFilter[] mFilters = NO_FILTERS;
private static final Spanned EMPTY_SPANNED = new SpannedString("");
+ private static int DRAG_THUMBNAIL_MAX_TEXT_LENGTH = 20;
}
diff --git a/core/res/res/layout/text_drag_thumbnail.xml b/core/res/res/layout/text_drag_thumbnail.xml
new file mode 100644
index 000000000000..63d2c05b539e
--- /dev/null
+++ b/core/res/res/layout/text_drag_thumbnail.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2010, 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.
+*/
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@android:style/TextAppearance.Large"
+ android:gravity="center"
+ />