Merge "Fix remote input view clobbering" into nyc-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d7705b9..d2dc7b7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3351,7 +3351,8 @@
}
private void resetStandardTemplateWithActions(RemoteViews big) {
- big.setViewVisibility(R.id.actions_container, View.GONE);
+ // actions_container is only reset when there are no actions to avoid focus issues with
+ // remote inputs.
big.setViewVisibility(R.id.actions, View.GONE);
big.removeAllViews(R.id.actions);
@@ -3396,6 +3397,8 @@
}
big.addView(R.id.actions, button);
}
+ } else {
+ big.setViewVisibility(R.id.actions_container, View.GONE);
}
CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 7be50c4..81303fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.app.Notification;
+import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.graphics.Rect;
@@ -118,6 +119,8 @@
private int mTransformationStartVisibleType;
private boolean mUserExpanding;
private int mSingleLineWidthIndention;
+ private PendingIntent mPreviousExpandedRemoteInputIntent;
+ private PendingIntent mPreviousHeadsUpRemoteInputIntent;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -280,13 +283,19 @@
mContractedChild.animate().cancel();
removeView(mContractedChild);
}
+ mPreviousExpandedRemoteInputIntent =
+ mExpandedRemoteInput != null ? mExpandedRemoteInput.getPendingIntent() : null;
if (mExpandedChild != null) {
mExpandedChild.animate().cancel();
removeView(mExpandedChild);
+ mExpandedRemoteInput = null;
}
+ mPreviousHeadsUpRemoteInputIntent =
+ mHeadsUpRemoteInput != null ? mHeadsUpRemoteInput.getPendingIntent() : null;
if (mHeadsUpChild != null) {
mHeadsUpChild.animate().cancel();
removeView(mHeadsUpChild);
+ mHeadsUpRemoteInput = null;
}
mContractedChild = null;
mExpandedChild = null;
@@ -496,6 +505,12 @@
}
int visibleType = calculateVisibleType();
if (visibleType != mVisibleType || force) {
+ View visibleView = getViewForVisibleType(visibleType);
+ if (visibleView != null) {
+ visibleView.setVisibility(VISIBLE);
+ transferRemoteInputFocus(visibleType);
+ }
+
if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
|| (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
|| (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
@@ -559,6 +574,19 @@
});
}
+ private void transferRemoteInputFocus(int visibleType) {
+ if (visibleType == VISIBLE_TYPE_HEADSUP
+ && mHeadsUpRemoteInput != null
+ && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
+ mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
+ }
+ if (visibleType == VISIBLE_TYPE_EXPANDED
+ && mExpandedRemoteInput != null
+ && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
+ mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
+ }
+ }
+
/**
* @param visibleType one of the static enum types in this view
* @return the corresponding transformable view according to the given visible type
@@ -736,6 +764,8 @@
updateShowingLegacyBackground();
selectLayout(false /* animate */, true /* force */);
setDark(mDark, false /* animate */, 0 /* delay */);
+ mPreviousExpandedRemoteInputIntent = null;
+ mPreviousHeadsUpRemoteInputIntent = null;
}
private void updateSingleLineView() {
@@ -771,19 +801,23 @@
View bigContentView = mExpandedChild;
if (bigContentView != null) {
- mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput);
+ mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
+ mPreviousExpandedRemoteInputIntent);
} else {
mExpandedRemoteInput = null;
}
+
View headsUpContentView = mHeadsUpChild;
if (headsUpContentView != null) {
- mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+ mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
+ mPreviousHeadsUpRemoteInputIntent);
} else {
mHeadsUpRemoteInput = null;
}
}
- private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
+ private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
+ boolean hasRemoteInput, PendingIntent existingPendingIntent) {
View actionContainerCandidate = view.findViewById(
com.android.internal.R.id.actions_container);
if (actionContainerCandidate instanceof FrameLayout) {
@@ -814,6 +848,24 @@
existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
mContext.getColor(R.color.remote_input_text),
mContext.getColor(R.color.remote_input_hint)));
+
+ if (existingPendingIntent != null || existing.isActive()) {
+ // The current action could be gone, or the pending intent no longer valid.
+ // If we find a matching action in the new notification, focus, otherwise close.
+ Notification.Action[] actions = entry.notification.getNotification().actions;
+ if (existingPendingIntent != null) {
+ existing.setPendingIntent(existingPendingIntent);
+ }
+ if (existing.updatePendingIntentFromActions(actions)) {
+ if (!existing.isActive()) {
+ existing.focus();
+ }
+ } else {
+ if (existing.isActive()) {
+ existing.close();
+ }
+ }
+ }
}
return existing;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index ecd1772..0fdd99f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
@@ -197,6 +198,7 @@
}
public void focus() {
+ setVisibility(VISIBLE);
mController.addRemoteInput(mEntry);
mEditText.setInnerFocusable(true);
mEditText.mShowImeOnInputConnection = true;
@@ -275,6 +277,63 @@
}
}
+ public boolean isActive() {
+ return mEditText.isFocused();
+ }
+
+ public void stealFocusFrom(RemoteInputView other) {
+ other.close();
+ setPendingIntent(other.mPendingIntent);
+ setRemoteInput(other.mRemoteInputs, other.mRemoteInput);
+ focus();
+ }
+
+ /**
+ * Tries to find an action in {@param actions} that matches the current pending intent
+ * of this view and updates its state to that of the found action
+ *
+ * @return true if a matching action was found, false otherwise
+ */
+ public boolean updatePendingIntentFromActions(Notification.Action[] actions) {
+ boolean found = false;
+ if (mPendingIntent == null || actions == null) {
+ return false;
+ }
+ Intent current = mPendingIntent.getIntent();
+ if (current == null) {
+ return false;
+ }
+
+ for (Notification.Action a : actions) {
+ RemoteInput[] inputs = a.getRemoteInputs();
+ if (a.actionIntent == null || inputs == null) {
+ continue;
+ }
+ Intent candidate = a.actionIntent.getIntent();
+ if (!current.filterEquals(candidate)) {
+ continue;
+ }
+
+ RemoteInput input = null;
+ for (RemoteInput i : inputs) {
+ if (i.getAllowFreeFormInput()) {
+ input = i;
+ }
+ }
+ if (input == null) {
+ continue;
+ }
+ setPendingIntent(a.actionIntent);
+ setRemoteInput(inputs, input);
+ return true;
+ }
+ return false;
+ }
+
+ public PendingIntent getPendingIntent() {
+ return mPendingIntent;
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.