Disabled reply action when pending intents are cancelled

Previously the user could open inline reply even when the
action was already cancelled. This also enables listening
to pending intent cancellations.

Test: manual
Fixes: 77811784
Change-Id: I4ae164081c6abdeb60a8e78d61bf5e4f26cca1d3
This commit is contained in:
Selim Cinek
2018-04-18 14:34:27 +08:00
parent 384804b42d
commit d83203cde4
6 changed files with 166 additions and 1 deletions

View File

@@ -33,8 +33,11 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.IResultReceiver;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -93,7 +96,9 @@ import java.lang.annotation.RetentionPolicy;
*/
public final class PendingIntent implements Parcelable {
private final IIntentSender mTarget;
private IResultReceiver mCancelReceiver;
private IBinder mWhitelistToken;
private ArraySet<CancelListener> mCancelListeners;
/** @hide */
@IntDef(flag = true,
@@ -963,6 +968,74 @@ public final class PendingIntent implements Parcelable {
}
}
/**
* Register a listener to when this pendingIntent is cancelled. There are no guarantees on which
* thread a listener will be called and it's up to the caller to synchronize. This may
* trigger a synchronous binder call so should therefore usually be called on a background
* thread.
*
* @hide
*/
public void registerCancelListener(CancelListener cancelListener) {
synchronized (this) {
if (mCancelReceiver == null) {
mCancelReceiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
notifyCancelListeners();
}
};
}
if (mCancelListeners == null) {
mCancelListeners = new ArraySet<>();
}
boolean wasEmpty = mCancelListeners.isEmpty();
mCancelListeners.add(cancelListener);
if (wasEmpty) {
try {
ActivityManager.getService().registerIntentSenderCancelListener(mTarget,
mCancelReceiver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
private void notifyCancelListeners() {
ArraySet<CancelListener> cancelListeners;
synchronized (this) {
cancelListeners = new ArraySet<>(mCancelListeners);
}
int size = cancelListeners.size();
for (int i = 0; i < size; i++) {
cancelListeners.valueAt(i).onCancelled(this);
}
}
/**
* Un-register a listener to when this pendingIntent is cancelled.
*
* @hide
*/
public void unregisterCancelListener(CancelListener cancelListener) {
synchronized (this) {
if (mCancelListeners == null) {
return;
}
boolean wasEmpty = mCancelListeners.isEmpty();
mCancelListeners.remove(cancelListener);
if (mCancelListeners.isEmpty() && !wasEmpty) {
try {
ActivityManager.getService().unregisterIntentSenderCancelListener(mTarget,
mCancelReceiver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
/**
* Return the user handle of the application that created this
* PendingIntent, that is the user under which you will actually be
@@ -1184,4 +1257,18 @@ public final class PendingIntent implements Parcelable {
public IBinder getWhitelistToken() {
return mWhitelistToken;
}
/**
* A listener to when a pending intent is cancelled
*
* @hide
*/
public interface CancelListener {
/**
* Called when a Pending Intent is cancelled.
*
* @param intent The intent that was cancelled.
*/
void onCancelled(PendingIntent intent);
}
}

View File

@@ -946,6 +946,7 @@ public class RemoteViews implements Parcelable, Filter {
}
};
}
target.setTagInternal(R.id.pending_intent_tag, pendingIntent);
target.setOnClickListener(listener);
}