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
This commit is contained in:
committed by
Android (Google) Code Review
parent
8983d11c40
commit
8cd8135b95
@@ -22969,9 +22969,13 @@ package android.text.style {
|
||||
|
||||
public class EasyEditSpan implements android.text.ParcelableSpan {
|
||||
ctor public EasyEditSpan();
|
||||
ctor public EasyEditSpan(android.app.PendingIntent);
|
||||
ctor public EasyEditSpan(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public int getSpanTypeId();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final java.lang.String ACTION_TEXT_DELETED = "android.text.style.TEXT_DELETED";
|
||||
field public static final java.lang.String ACTION_TEXT_MODIFIED = "android.text.style.TEXT_MODIFIED";
|
||||
}
|
||||
|
||||
public class ForegroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,18 +2027,28 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user