diff options
author | Luca Zanolin <zano@google.com> | 2013-02-14 14:18:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-02-20 11:35:19 +0000 |
commit | 8cd8135b95da5b471804604b06084eecbe1cc23b (patch) | |
tree | 4c2bc2ba891f16b32bfff70f5994ab1ecfc56a1a /core/java | |
parent | 8983d11c4069bc136f496987f11df7dcd5771188 (diff) | |
download | frameworks_base-8cd8135b95da5b471804604b06084eecbe1cc23b.zip frameworks_base-8cd8135b95da5b471804604b06084eecbe1cc23b.tar.gz frameworks_base-8cd8135b95da5b471804604b06084eecbe1cc23b.tar.bz2 |
Enable correction/deleting notification via EasyEditSpan.
When the "delete" pop-up is clicked (and the wrapped text removed), the
creator of the span will receive a notification of the action.
Similarly, if the user modifies (i.e., add/remove a char), the creator of
the span will receive a notification too. The notification will not contain any
information about how the text has been modified.
Bug: 6905960
Change-Id: Ic227b8fd50066699915f69a54f225fb5330867c4
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/text/TextUtils.java | 2 | ||||
-rw-r--r-- | core/java/android/text/style/EasyEditSpan.java | 85 | ||||
-rw-r--r-- | core/java/android/widget/Editor.java | 73 |
3 files changed, 146 insertions, 14 deletions
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 1508d10..2ab9bf8 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -757,7 +757,7 @@ public class TextUtils { break; case EASY_EDIT_SPAN: - readSpan(p, sp, new EasyEditSpan()); + readSpan(p, sp, new EasyEditSpan(p)); break; case LOCALE_SPAN: diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java index 2feb719..03b4f60 100644 --- a/core/java/android/text/style/EasyEditSpan.java +++ b/core/java/android/text/style/EasyEditSpan.java @@ -16,6 +16,7 @@ package android.text.style; +import android.app.PendingIntent; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextUtils; @@ -25,12 +26,62 @@ import android.widget.TextView; * Provides an easy way to edit a portion of text. * <p> * The {@link TextView} uses this span to allow the user to delete a chuck of text in one click. - * the text. {@link TextView} removes this span as soon as the text is edited, or the cursor moves. + * <p> + * {@link TextView} removes the span when the user deletes the whole text or modifies it. + * <p> + * This span can be also used to receive notification when the user deletes or modifies the text; */ public class EasyEditSpan implements ParcelableSpan { + /** + * The extra key field in the pending intent that describes how the text changed. + * + * @see #TEXT_DELETED + * @see #TEXT_MODIFIED + * @see #getPendingIntent() + */ + public static final String EXTRA_TEXT_CHANGED_TYPE = + "android.text.style.EXTRA_TEXT_CHANGED_TYPE"; + + /** + * The value of {@link #EXTRA_TEXT_CHANGED_TYPE} when the text wrapped by this span is deleted. + */ + public static final int TEXT_DELETED = 1; + + /** + * The value of {@link #EXTRA_TEXT_CHANGED_TYPE} when the text wrapped by this span is modified. + */ + public static final int TEXT_MODIFIED = 2; + + private final PendingIntent mPendingIntent; + + private boolean mDeleteEnabled; + + /** + * Creates the span. No intent is sent when the wrapped text is modified or + * deleted. + */ public EasyEditSpan() { - // Empty + mPendingIntent = null; + mDeleteEnabled = true; + } + + /** + * @param pendingIntent The intent will be sent when the wrapped text is deleted or modified. + * When the pending intent is sent, {@link #EXTRA_TEXT_CHANGED_TYPE} is + * added in the intent to describe how the text changed. + */ + public EasyEditSpan(PendingIntent pendingIntent) { + mPendingIntent = pendingIntent; + mDeleteEnabled = true; + } + + /** + * Constructor called from {@link TextUtils} to restore the span. + */ + public EasyEditSpan(Parcel source) { + mPendingIntent = source.readParcelable(null); + mDeleteEnabled = (source.readByte() == 1); } @Override @@ -40,11 +91,39 @@ public class EasyEditSpan implements ParcelableSpan { @Override public void writeToParcel(Parcel dest, int flags) { - // Empty + dest.writeParcelable(mPendingIntent, 0); + dest.writeByte((byte) (mDeleteEnabled ? 1 : 0)); } @Override public int getSpanTypeId() { return TextUtils.EASY_EDIT_SPAN; } + + /** + * @return True if the {@link TextView} should offer the ability to delete the text. + * + * @hide + */ + public boolean isDeleteEnabled() { + return mDeleteEnabled; + } + + /** + * Enables or disables the deletion of the text. + * + * @hide + */ + public void setDeleteEnabled(boolean value) { + mDeleteEnabled = value; + } + + /** + * @return the pending intent to send when the wrapped text is deleted or modified. + * + * @hide + */ + public PendingIntent getPendingIntent() { + return mPendingIntent; + } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 862e2c8..dc305a5 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -20,6 +20,8 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.widget.EditableInputConnection; import android.R; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; import android.content.ClipData; import android.content.ClipData.Item; import android.content.Context; @@ -1890,10 +1892,23 @@ public class Editor { // Make sure there is only at most one EasyEditSpan in the text if (mPopupWindow.mEasyEditSpan != null) { - text.removeSpan(mPopupWindow.mEasyEditSpan); + mPopupWindow.mEasyEditSpan.setDeleteEnabled(false); } mPopupWindow.setEasyEditSpan((EasyEditSpan) span); + mPopupWindow.setOnDeleteListener(new EasyEditDeleteListener() { + @Override + public void onDeleteClick(EasyEditSpan span) { + Editable editable = (Editable) mTextView.getText(); + int start = editable.getSpanStart(span); + int end = editable.getSpanEnd(span); + if (start >= 0 && end >= 0) { + sendNotification(EasyEditSpan.TEXT_DELETED, span); + mTextView.deleteText_internal(start, end); + } + editable.removeSpan(span); + } + }); if (mTextView.getWindowVisibility() != View.VISIBLE) { // The window is not visible yet, ignore the text change. @@ -1927,8 +1942,10 @@ public class Editor { @Override public void onSpanChanged(Spannable text, Object span, int previousStart, int previousEnd, int newStart, int newEnd) { - if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) { - text.removeSpan(mPopupWindow.mEasyEditSpan); + if (mPopupWindow != null && span instanceof EasyEditSpan) { + EasyEditSpan easyEditSpan = (EasyEditSpan) span; + sendNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan); + text.removeSpan(easyEditSpan); } } @@ -1938,6 +1955,31 @@ public class Editor { mTextView.removeCallbacks(mHidePopup); } } + + private void sendNotification(int textChangedType, EasyEditSpan span) { + try { + PendingIntent pendingIntent = span.getPendingIntent(); + if (pendingIntent != null) { + Intent intent = new Intent(); + intent.putExtra(EasyEditSpan.EXTRA_TEXT_CHANGED_TYPE, textChangedType); + pendingIntent.send(mTextView.getContext(), 0, intent); + } + } catch (CanceledException e) { + // This should not happen, as we should try to send the intent only once. + Log.w(TAG, "PendingIntent for notification cannot be sent", e); + } + } + } + + /** + * Listens for the delete event triggered by {@link EasyEditPopupWindow}. + */ + private interface EasyEditDeleteListener { + + /** + * Clicks the delete pop-up. + */ + void onDeleteClick(EasyEditSpan span); } /** @@ -1950,6 +1992,7 @@ public class Editor { com.android.internal.R.layout.text_edit_action_popup_text; private TextView mDeleteTextView; private EasyEditSpan mEasyEditSpan; + private EasyEditDeleteListener mOnDeleteListener; @Override protected void createPopupWindow() { @@ -1984,19 +2027,29 @@ public class Editor { mEasyEditSpan = easyEditSpan; } + private void setOnDeleteListener(EasyEditDeleteListener listener) { + mOnDeleteListener = listener; + } + @Override public void onClick(View view) { - if (view == mDeleteTextView) { - Editable editable = (Editable) mTextView.getText(); - int start = editable.getSpanStart(mEasyEditSpan); - int end = editable.getSpanEnd(mEasyEditSpan); - if (start >= 0 && end >= 0) { - mTextView.deleteText_internal(start, end); - } + if (view == mDeleteTextView + && mEasyEditSpan != null && mEasyEditSpan.isDeleteEnabled() + && mOnDeleteListener != null) { + mOnDeleteListener.onDeleteClick(mEasyEditSpan); } } @Override + public void hide() { + if (mEasyEditSpan != null) { + mEasyEditSpan.setDeleteEnabled(false); + } + mOnDeleteListener = null; + super.hide(); + } + + @Override protected int getTextOffset() { // Place the pop-up at the end of the span Editable editable = (Editable) mTextView.getText(); |