Merge "Add setEditChoicesBeforeSending to RemoteInput"
This commit is contained in:
@@ -5983,6 +5983,7 @@ package android.app {
|
||||
method public java.util.Set<java.lang.String> getAllowedDataTypes();
|
||||
method public java.lang.CharSequence[] getChoices();
|
||||
method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
|
||||
method public int getEditChoicesBeforeSending();
|
||||
method public android.os.Bundle getExtras();
|
||||
method public java.lang.CharSequence getLabel();
|
||||
method public java.lang.String getResultKey();
|
||||
@@ -5992,6 +5993,9 @@ package android.app {
|
||||
method public static void setResultsSource(android.content.Intent, int);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
|
||||
field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
|
||||
field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
|
||||
field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
|
||||
field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
|
||||
field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
|
||||
field public static final int SOURCE_CHOICE = 1; // 0x1
|
||||
@@ -6006,6 +6010,7 @@ package android.app {
|
||||
method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
|
||||
method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
|
||||
method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
|
||||
method public android.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
|
||||
method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +93,22 @@ public final class RemoteInput implements Parcelable {
|
||||
/** The user selected one of the choices from {@link #getChoices}. */
|
||||
public static final int SOURCE_CHOICE = 1;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = {"EDIT_CHOICES_BEFORE_SENDING_"},
|
||||
value = {EDIT_CHOICES_BEFORE_SENDING_AUTO, EDIT_CHOICES_BEFORE_SENDING_DISABLED,
|
||||
EDIT_CHOICES_BEFORE_SENDING_ENABLED})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface EditChoicesBeforeSending {}
|
||||
|
||||
/** The platform will determine whether choices will be edited before being sent to the app. */
|
||||
public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0;
|
||||
|
||||
/** Tapping on a choice should send the input immediately, without letting the user edit it. */
|
||||
public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1;
|
||||
|
||||
/** Tapping on a choice should let the user edit the input before it is sent to the app. */
|
||||
public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2;
|
||||
|
||||
// Flags bitwise-ored to mFlags
|
||||
private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
|
||||
|
||||
@@ -103,17 +119,25 @@ public final class RemoteInput implements Parcelable {
|
||||
private final CharSequence mLabel;
|
||||
private final CharSequence[] mChoices;
|
||||
private final int mFlags;
|
||||
@EditChoicesBeforeSending private final int mEditChoicesBeforeSending;
|
||||
private final Bundle mExtras;
|
||||
private final ArraySet<String> mAllowedDataTypes;
|
||||
|
||||
private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
|
||||
int flags, Bundle extras, ArraySet<String> allowedDataTypes) {
|
||||
int flags, int editChoicesBeforeSending, Bundle extras,
|
||||
ArraySet<String> allowedDataTypes) {
|
||||
this.mResultKey = resultKey;
|
||||
this.mLabel = label;
|
||||
this.mChoices = choices;
|
||||
this.mFlags = flags;
|
||||
this.mEditChoicesBeforeSending = editChoicesBeforeSending;
|
||||
this.mExtras = extras;
|
||||
this.mAllowedDataTypes = allowedDataTypes;
|
||||
if (getEditChoicesBeforeSending() == EDIT_CHOICES_BEFORE_SENDING_ENABLED
|
||||
&& !getAllowFreeFormInput()) {
|
||||
throw new IllegalArgumentException(
|
||||
"setEditChoicesBeforeSending requires setAllowFreeFormInput");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,6 +192,15 @@ public final class RemoteInput implements Parcelable {
|
||||
return (mFlags & FLAG_ALLOW_FREE_FORM_INPUT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether tapping on a choice should let the user edit the input before it is sent to the
|
||||
* app.
|
||||
*/
|
||||
@EditChoicesBeforeSending
|
||||
public int getEditChoicesBeforeSending() {
|
||||
return mEditChoicesBeforeSending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get additional metadata carried around with this remote input.
|
||||
*/
|
||||
@@ -185,6 +218,8 @@ public final class RemoteInput implements Parcelable {
|
||||
private CharSequence mLabel;
|
||||
private CharSequence[] mChoices;
|
||||
private int mFlags = DEFAULT_FLAGS;
|
||||
@EditChoicesBeforeSending
|
||||
private int mEditChoicesBeforeSending = EDIT_CHOICES_BEFORE_SENDING_AUTO;
|
||||
|
||||
/**
|
||||
* Create a builder object for {@link RemoteInput} objects.
|
||||
@@ -269,7 +304,20 @@ public final class RemoteInput implements Parcelable {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) {
|
||||
setFlag(mFlags, allowFreeFormTextInput);
|
||||
setFlag(FLAG_ALLOW_FREE_FORM_INPUT, allowFreeFormTextInput);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether tapping on a choice should let the user edit the input before it is
|
||||
* sent to the app. The default is {@link #EDIT_CHOICES_BEFORE_SENDING_AUTO}.
|
||||
*
|
||||
* It cannot be used if {@link #setAllowFreeFormInput} has been set to false.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setEditChoicesBeforeSending(
|
||||
@EditChoicesBeforeSending int editChoicesBeforeSending) {
|
||||
mEditChoicesBeforeSending = editChoicesBeforeSending;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -312,8 +360,8 @@ public final class RemoteInput implements Parcelable {
|
||||
*/
|
||||
@NonNull
|
||||
public RemoteInput build() {
|
||||
return new RemoteInput(
|
||||
mResultKey, mLabel, mChoices, mFlags, mExtras, mAllowedDataTypes);
|
||||
return new RemoteInput(mResultKey, mLabel, mChoices, mFlags, mEditChoicesBeforeSending,
|
||||
mExtras, mAllowedDataTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,6 +370,7 @@ public final class RemoteInput implements Parcelable {
|
||||
mLabel = in.readCharSequence();
|
||||
mChoices = in.readCharSequenceArray();
|
||||
mFlags = in.readInt();
|
||||
mEditChoicesBeforeSending = in.readInt();
|
||||
mExtras = in.readBundle();
|
||||
mAllowedDataTypes = (ArraySet<String>) in.readArraySet(null);
|
||||
}
|
||||
@@ -507,6 +556,7 @@ public final class RemoteInput implements Parcelable {
|
||||
out.writeCharSequence(mLabel);
|
||||
out.writeCharSequenceArray(mChoices);
|
||||
out.writeInt(mFlags);
|
||||
out.writeInt(mEditChoicesBeforeSending);
|
||||
out.writeBundle(mExtras);
|
||||
out.writeArraySet(mAllowedDataTypes);
|
||||
}
|
||||
|
||||
@@ -218,88 +218,7 @@ public class NotificationRemoteInputManager implements Dumpable {
|
||||
return false;
|
||||
}
|
||||
|
||||
ViewParent p = view.getParent();
|
||||
RemoteInputView riv = null;
|
||||
while (p != null) {
|
||||
if (p instanceof View) {
|
||||
View pv = (View) p;
|
||||
if (pv.isRootNamespace()) {
|
||||
riv = findRemoteInputView(pv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
ExpandableNotificationRow row = null;
|
||||
while (p != null) {
|
||||
if (p instanceof ExpandableNotificationRow) {
|
||||
row = (ExpandableNotificationRow) p;
|
||||
break;
|
||||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
|
||||
if (row == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
row.setUserExpanded(true);
|
||||
|
||||
if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
|
||||
final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
|
||||
if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
|
||||
mCallback.onLockedRemoteInput(row, view);
|
||||
return true;
|
||||
}
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()
|
||||
&& mKeyguardManager.isDeviceLocked(userId)) {
|
||||
mCallback.onLockedWorkRemoteInput(userId, row, view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (riv == null) {
|
||||
riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
|
||||
if (riv == null) {
|
||||
return false;
|
||||
}
|
||||
if (!row.getPrivateLayout().getExpandedChild().isShown()) {
|
||||
mCallback.onMakeExpandedVisibleForRemoteInput(row, view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int width = view.getWidth();
|
||||
if (view instanceof TextView) {
|
||||
// Center the reveal on the text which might be off-center from the TextView
|
||||
TextView tv = (TextView) view;
|
||||
if (tv.getLayout() != null) {
|
||||
int innerWidth = (int) tv.getLayout().getLineWidth(0);
|
||||
innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
|
||||
width = Math.min(width, innerWidth);
|
||||
}
|
||||
}
|
||||
int cx = view.getLeft() + width / 2;
|
||||
int cy = view.getTop() + view.getHeight() / 2;
|
||||
int w = riv.getWidth();
|
||||
int h = riv.getHeight();
|
||||
int r = Math.max(
|
||||
Math.max(cx + cy, cx + (h - cy)),
|
||||
Math.max((w - cx) + cy, (w - cx) + (h - cy)));
|
||||
|
||||
riv.setRevealParameters(cx, cy, r);
|
||||
riv.setPendingIntent(pendingIntent);
|
||||
riv.setRemoteInput(inputs, input);
|
||||
riv.focusAnimated();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private RemoteInputView findRemoteInputView(View v) {
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
|
||||
return activateRemoteInput(view, inputs, input, pendingIntent);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -354,6 +273,102 @@ public class NotificationRemoteInputManager implements Dumpable {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a given {@link RemoteInput}
|
||||
*
|
||||
* @param view The view of the action button or suggestion chip that was tapped.
|
||||
* @param inputs The remote inputs that need to be sent to the app.
|
||||
* @param input The remote input that needs to be activated.
|
||||
* @param pendingIntent The pending intent to be sent to the app.
|
||||
* @return Whether the {@link RemoteInput} was activated.
|
||||
*/
|
||||
public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
|
||||
PendingIntent pendingIntent) {
|
||||
|
||||
ViewParent p = view.getParent();
|
||||
RemoteInputView riv = null;
|
||||
while (p != null) {
|
||||
if (p instanceof View) {
|
||||
View pv = (View) p;
|
||||
if (pv.isRootNamespace()) {
|
||||
riv = findRemoteInputView(pv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
ExpandableNotificationRow row = null;
|
||||
while (p != null) {
|
||||
if (p instanceof ExpandableNotificationRow) {
|
||||
row = (ExpandableNotificationRow) p;
|
||||
break;
|
||||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
|
||||
if (row == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
row.setUserExpanded(true);
|
||||
|
||||
if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
|
||||
final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
|
||||
if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
|
||||
mCallback.onLockedRemoteInput(row, view);
|
||||
return true;
|
||||
}
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()
|
||||
&& mKeyguardManager.isDeviceLocked(userId)) {
|
||||
mCallback.onLockedWorkRemoteInput(userId, row, view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (riv == null) {
|
||||
riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
|
||||
if (riv == null) {
|
||||
return false;
|
||||
}
|
||||
if (!row.getPrivateLayout().getExpandedChild().isShown()) {
|
||||
mCallback.onMakeExpandedVisibleForRemoteInput(row, view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int width = view.getWidth();
|
||||
if (view instanceof TextView) {
|
||||
// Center the reveal on the text which might be off-center from the TextView
|
||||
TextView tv = (TextView) view;
|
||||
if (tv.getLayout() != null) {
|
||||
int innerWidth = (int) tv.getLayout().getLineWidth(0);
|
||||
innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
|
||||
width = Math.min(width, innerWidth);
|
||||
}
|
||||
}
|
||||
int cx = view.getLeft() + width / 2;
|
||||
int cy = view.getTop() + view.getHeight() / 2;
|
||||
int w = riv.getWidth();
|
||||
int h = riv.getHeight();
|
||||
int r = Math.max(
|
||||
Math.max(cx + cy, cx + (h - cy)),
|
||||
Math.max((w - cx) + cy, (w - cx) + (h - cy)));
|
||||
|
||||
riv.setRevealParameters(cx, cy, r);
|
||||
riv.setPendingIntent(pendingIntent);
|
||||
riv.setRemoteInput(inputs, input);
|
||||
riv.focusAnimated();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private RemoteInputView findRemoteInputView(View v) {
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the notification lifetime extenders. Each extender represents a reason for the
|
||||
* NotificationRemoteInputManager to keep a notification lifetime extended.
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
import com.android.systemui.statusbar.SmartReplyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationData;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
@@ -63,6 +64,7 @@ public class SmartReplyView extends ViewGroup {
|
||||
|
||||
private final SmartReplyConstants mConstants;
|
||||
private final KeyguardDismissUtil mKeyguardDismissUtil;
|
||||
private final NotificationRemoteInputManager mRemoteInputManager;
|
||||
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
/**
|
||||
@@ -112,6 +114,7 @@ public class SmartReplyView extends ViewGroup {
|
||||
super(context, attrs);
|
||||
mConstants = Dependency.get(SmartReplyConstants.class);
|
||||
mKeyguardDismissUtil = Dependency.get(KeyguardDismissUtil.class);
|
||||
mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
|
||||
|
||||
mHeightUpperLimit = NotificationUtils.getFontScaledHeight(mContext,
|
||||
R.dimen.smart_reply_button_max_height);
|
||||
@@ -242,12 +245,22 @@ public class SmartReplyView extends ViewGroup {
|
||||
b.setText(choice);
|
||||
|
||||
OnDismissAction action = () -> {
|
||||
// TODO(b/111437455): Also for EDIT_CHOICES_BEFORE_SENDING_AUTO, depending on flags.
|
||||
if (smartReplies.remoteInput.getEditChoicesBeforeSending()
|
||||
== RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED) {
|
||||
entry.remoteInputText = choice;
|
||||
mRemoteInputManager.activateRemoteInput(b,
|
||||
new RemoteInput[] { smartReplies.remoteInput }, smartReplies.remoteInput,
|
||||
smartReplies.pendingIntent);
|
||||
return false;
|
||||
}
|
||||
|
||||
smartReplyController.smartReplySent(
|
||||
entry, replyIndex, b.getText(), smartReplies.fromAssistant);
|
||||
Bundle results = new Bundle();
|
||||
results.putString(smartReplies.remoteInput.getResultKey(), choice.toString());
|
||||
Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
RemoteInput.addResultsToIntent(new RemoteInput[]{smartReplies.remoteInput}, intent,
|
||||
RemoteInput.addResultsToIntent(new RemoteInput[] { smartReplies.remoteInput }, intent,
|
||||
results);
|
||||
RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE);
|
||||
entry.setHasSentReply();
|
||||
|
||||
Reference in New Issue
Block a user