diff --git a/packages/SystemUI/res/drawable/rounded_rect_background.xml b/packages/SystemUI/res/drawable/rounded_rect_background.xml
new file mode 100644
index 0000000000000..83b0f7122169e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_rect_background.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/drawable/thumbnail_delete_btn_bg.xml b/packages/SystemUI/res/drawable/thumbnail_delete_btn_bg.xml
new file mode 100644
index 0000000000000..ea7d45d03b7f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/thumbnail_delete_btn_bg.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 4fcce243f58fc..a909d0d4d3c24 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -22,28 +22,75 @@
android:id="@+id/remote_input"
android:layout_height="match_parent"
android:layout_width="match_parent">
+
+
+
+
+
+
-
+
+
Num Lock
Numpad %1$s
-
+
+ Remove attachment
System
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 3bf0ddb1985b7..298d4f07a8df2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.row;
import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
@@ -93,14 +94,16 @@ public class FooterView extends StackScrollerDecorView {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ int textColor = getResources().getColor(R.color.notif_pill_text);
+ Resources.Theme theme = getContext().getTheme();
mDismissButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background));
- mDismissButton.setTextColor(getResources().getColor(R.color.notif_pill_text));
+ getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
+ mDismissButton.setTextColor(textColor);
mManageButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background));
- mManageButton.setTextColor(getResources().getColor(R.color.notif_pill_text));
+ getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
mManageButton = findViewById(R.id.manage_text);
mDismissButton.setText(R.string.clear_all_notifications_text);
+ mManageButton.setTextColor(textColor);
mDismissButton.setContentDescription(
mContext.getString(R.string.accessibility_clear_all));
showHistory(mShowHistory);
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 f2a0e37868852..a3fd92f8e186c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -25,21 +25,18 @@ import android.app.ActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
-import android.content.ClipData;
-import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
+import android.graphics.BlendMode;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.ServiceManager;
@@ -47,7 +44,9 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.text.Editable;
import android.text.SpannedString;
+import android.text.TextUtils;
import android.text.TextWatcher;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
@@ -68,6 +67,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -81,7 +81,6 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -89,6 +88,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry.
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.wm.shell.animation.Interpolators;
import java.util.ArrayList;
import java.util.Collection;
@@ -114,6 +114,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private final List mEditTextFocusChangeListeners = new ArrayList<>();
private RemoteEditText mEditText;
private ImageButton mSendButton;
+ private GradientDrawable mContentBackground;
private ProgressBar mProgressBar;
private PendingIntent mPendingIntent;
private RemoteInput[] mRemoteInputs;
@@ -130,6 +131,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private int mRevealCx;
private int mRevealCy;
private int mRevealR;
+ private ContentInfo mAttachment;
private boolean mColorized;
private int mTint;
@@ -138,6 +140,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private NotificationViewWrapper mWrapper;
private Consumer mOnVisibilityChangedListener;
private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
+ private LinearLayout mContentView;
+ private ImageView mDelete;
+ private ImageView mDeleteBg;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -149,7 +154,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
com.android.internal.R.attr.colorAccent,
- com.android.internal.R.attr.colorBackgroundFloating,
+ com.android.internal.R.attr.colorSurface,
});
mTint = ta.getColor(0, 0);
ta.recycle();
@@ -165,14 +170,20 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mColorized = colorized;
mTint = backgroundColor;
final int editBgColor;
+ final int alternateBgColor;
+ final int alternateTextColor;
final int accentColor;
final int textColor;
final int hintTextColor;
+ final int stroke = mContext.getResources().getDimensionPixelSize(
+ R.dimen.remote_input_view_text_stroke);
if (colorized) {
final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
final int foregroundColor = dark ? Color.WHITE : Color.BLACK;
editBgColor = backgroundColor;
accentColor = foregroundColor;
+ alternateBgColor = foregroundColor;
+ alternateTextColor = backgroundColor;
textColor = foregroundColor;
hintTextColor = ColorUtils.setAlphaComponent(foregroundColor, 0x99);
} else {
@@ -180,10 +191,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
hintTextColor = mContext.getColor(R.color.remote_input_hint);
try (TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
com.android.internal.R.attr.colorAccent,
- com.android.internal.R.attr.colorBackgroundFloating,
+ com.android.internal.R.attr.colorSurface,
+ com.android.internal.R.attr.colorSurfaceVariant,
+ com.android.internal.R.attr.textColorPrimary
})) {
accentColor = ta.getColor(0, textColor);
editBgColor = ta.getColor(1, backgroundColor);
+ alternateBgColor = ta.getColor(2, textColor);
+ alternateTextColor = ta.getColor(3, backgroundColor);
}
}
mEditText.setAllColors(backgroundColor, editBgColor,
@@ -195,11 +210,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
accentColor,
accentColor & 0x4DFFFFFF // %30 opacity
});
+ mContentBackground.setColor(editBgColor);
+ mContentBackground.setStroke(stroke, accentTint);
+ mDelete.setImageTintList(ColorStateList.valueOf(alternateTextColor));
+ mDeleteBg.setImageTintList(ColorStateList.valueOf(alternateBgColor));
mSendButton.setImageTintList(accentTint);
mProgressBar.setProgressTintList(accentTint);
mProgressBar.setIndeterminateTintList(accentTint);
mProgressBar.setSecondaryProgressTintList(accentTint);
- setBackgroundColor(backgroundColor);
+ setBackgroundColor(editBgColor);
}
@Override
@@ -209,8 +228,16 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mProgressBar = findViewById(R.id.remote_input_progress);
mSendButton = findViewById(R.id.remote_input_send);
mSendButton.setOnClickListener(this);
-
- mEditText = (RemoteEditText) getChildAt(0);
+ mContentBackground = (GradientDrawable)
+ mContext.getDrawable(R.drawable.remote_input_view_text_bg).mutate();
+ mDelete = findViewById(R.id.remote_input_delete);
+ mDeleteBg = findViewById(R.id.remote_input_delete_bg);
+ mDeleteBg.setImageTintBlendMode(BlendMode.SRC_IN);
+ mDelete.setImageTintBlendMode(BlendMode.SRC_IN);
+ mDelete.setOnClickListener(v -> setAttachment(null));
+ mContentView = findViewById(R.id.remote_input_content);
+ mContentView.setBackground(mContentBackground);
+ mEditText = findViewById(R.id.remote_input_text);
mEditText.setInnerFocusable(false);
mEditText.setWindowInsetsAnimationCallback(
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -220,7 +247,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@NonNull List runningAnimations) {
return insets;
}
-
@Override
public void onEnd(@NonNull WindowInsetsAnimation animation) {
super.onEnd(animation);
@@ -235,7 +261,43 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
});
}
- protected Intent prepareRemoteInputFromText() {
+ private void setAttachment(ContentInfo item) {
+ if (mAttachment != null) {
+ // We need to release permissions when sending the attachment to the target
+ // app or if it is deleted by the user. When sending to the target app, we
+ // can safely release permissions as soon as the call to
+ // `mController.grantInlineReplyUriPermission` is made (ie, after the grant
+ // to the target app has been created).
+ mAttachment.releasePermissions();
+ }
+ mAttachment = item;
+ View attachment = findViewById(R.id.remote_input_content_container);
+ ImageView iconView = findViewById(R.id.remote_input_attachment_image);
+ iconView.setImageDrawable(null);
+ if (item == null) {
+ attachment.setVisibility(GONE);
+ return;
+ }
+ iconView.setImageURI(item.getClip().getItemAt(0).getUri());
+ if (iconView.getDrawable() == null) {
+ attachment.setVisibility(GONE);
+ } else {
+ attachment.setVisibility(VISIBLE);
+ }
+ }
+
+ /**
+ * Reply intent
+ * @return returns intent with granted URI permissions that should be used immediately
+ */
+ private Intent prepareRemoteInput() {
+ if (mAttachment == null) return prepareRemoteInputFromText();
+ return prepareRemoteInputFromData(
+ mAttachment.getClip().getDescription().getMimeType(0),
+ mAttachment.getClip().getItemAt(0).getUri());
+ }
+
+ private Intent prepareRemoteInputFromText() {
Bundle results = new Bundle();
results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -255,17 +317,40 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return fillInIntent;
}
- protected Intent prepareRemoteInputFromData(String contentType, Uri data) {
+ private Intent prepareRemoteInputFromData(String contentType, Uri data) {
HashMap results = new HashMap<>();
results.put(contentType, data);
+ // grant for the target app.
mController.grantInlineReplyUriPermission(mEntry.getSbn(), data);
Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
RemoteInput.addDataResultToIntent(mRemoteInput, fillInIntent, results);
- mEntry.remoteInputText = mContext.getString(R.string.remote_input_image_insertion_text);
+ Bundle bundle = new Bundle();
+ bundle.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
+ RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
+ bundle);
+
+ CharSequence attachmentText = mAttachment.getClip().getDescription().getLabel();
+
+ CharSequence attachmentLabel = TextUtils.isEmpty(attachmentText)
+ ? mContext.getString(R.string.remote_input_image_insertion_text)
+ : attachmentText;
+ // add content description to reply text for context
+ CharSequence fullText = TextUtils.isEmpty(mEditText.getText())
+ ? attachmentLabel
+ : "\"" + attachmentLabel + "\" " + mEditText.getText();
+
+ mEntry.remoteInputText = fullText;
mEntry.remoteInputMimeType = contentType;
mEntry.remoteInputUri = data;
+ // mirror prepareRemoteInputFromText for text input
+ if (mEntry.editedSuggestionInfo == null) {
+ RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT);
+ } else if (mAttachment == null) {
+ RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE);
+ }
+
return fillInIntent;
}
@@ -303,6 +388,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_FAIL,
mEntry.getSbn().getPackageName());
}
+ setAttachment(null);
}
public CharSequence getText() {
@@ -327,7 +413,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
public void onClick(View v) {
if (v == mSendButton) {
- sendRemoteInput(prepareRemoteInputFromText());
+ sendRemoteInput(prepareRemoteInput());
}
}
@@ -682,8 +768,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
&& event.getAction() == KeyEvent.ACTION_DOWN;
if (isSoftImeEvent || isKeyboardEnterKey) {
- if (mEditText.length() > 0) {
- sendRemoteInput(prepareRemoteInputFromText());
+ if (mEditText.length() > 0 || mAttachment != null) {
+ sendRemoteInput(prepareRemoteInput());
}
// Consume action to prevent IME from closing.
return true;
@@ -716,21 +802,18 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private final OnReceiveContentListener mOnReceiveContentListener = this::onReceiveContent;
private RemoteInputView mRemoteInputView;
- private GradientDrawable mTextBackground;
- private ColorDrawable mBackgroundColor;
- private LayerDrawable mBackground;
+ private ColorDrawable mBackground;
boolean mShowImeOnInputConnection;
private LightBarController mLightBarController;
private InputMethodManager mInputMethodManager;
+ private ArraySet mSupportedMimes = new ArraySet<>();
UserHandle mUser;
public RemoteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mLightBarController = Dependency.get(LightBarController.class);
- mTextBackground = (GradientDrawable)
- context.getDrawable(R.drawable.remote_input_view_text_bg).mutate();
- mBackgroundColor = new ColorDrawable();
- mBackground = new LayerDrawable(new Drawable[] {mBackgroundColor, mTextBackground});
+
+ mBackground = new ColorDrawable();
}
void setSupportedMimeTypes(@Nullable Collection mimeTypes) {
@@ -741,6 +824,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
listener = mOnReceiveContentListener;
}
setOnReceiveContentListener(types, listener);
+ mSupportedMimes.clear();
+ mSupportedMimes.addAll(mimeTypes);
}
private void hideIme() {
@@ -899,36 +984,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
ContentInfo uriItems = split.first;
ContentInfo remainingItems = split.second;
if (uriItems != null) {
- ClipData clip = uriItems.getClip();
- ClipDescription description = clip.getDescription();
- if (clip.getItemCount() > 1
- || description.getMimeTypeCount() < 1
- || remainingItems != null) {
- // Direct-reply in notifications currently only supports only one uri item
- // at a time and requires the MIME type to be set.
- Log.w(TAG, "Invalid payload: " + payload);
- return payload;
- }
- Uri contentUri = clip.getItemAt(0).getUri();
- String mimeType = description.getMimeType(0);
- Intent dataIntent =
- mRemoteInputView.prepareRemoteInputFromData(mimeType, contentUri);
- // We can release the uri permissions granted to us as soon as we've created the
- // grant for the target app in the call above.
- payload.releasePermissions();
- mRemoteInputView.sendRemoteInput(dataIntent);
+ mRemoteInputView.setAttachment(uriItems);
}
return remainingItems;
}
protected void setAllColors(int backgroundColor, int editBackgroundColor,
int accentColor, int textColor, int hintTextColor) {
- setBackgroundColor(backgroundColor);
- mBackgroundColor.setColor(backgroundColor);
- mTextBackground.setColor(editBackgroundColor);
- int stroke = getContext().getResources()
- .getDimensionPixelSize(R.dimen.remote_input_view_text_stroke);
- mTextBackground.setStroke(stroke, accentColor);
+ setBackgroundColor(editBackgroundColor);
+ mBackground.setColor(editBackgroundColor);
setTextColor(textColor);
setHintTextColor(hintTextColor);
getTextCursorDrawable().setColorFilter(accentColor, PorterDuff.Mode.SRC_IN);