Merge "Persist remote input image attachment across layouts" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-06-29 18:00:38 +00:00
committed by Android (Google) Code Review
4 changed files with 40 additions and 46 deletions

View File

@@ -369,7 +369,7 @@ public class NotificationRemoteInputManager implements Dumpable {
});
mSmartReplyController.setCallback((entry, reply) -> {
StatusBarNotification newSbn =
rebuildNotificationWithRemoteInput(entry, reply, true /* showSpinner */,
rebuildNotificationWithRemoteInputInserted(entry, reply, true /* showSpinner */,
null /* mimeType */, null /* uri */);
mEntryManager.updateNotification(newSbn, null /* ranking */);
});
@@ -638,12 +638,12 @@ public class NotificationRemoteInputManager implements Dumpable {
@VisibleForTesting
StatusBarNotification rebuildNotificationForCanceledSmartReplies(
NotificationEntry entry) {
return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
return rebuildNotificationWithRemoteInputInserted(entry, null /* remoteInputTest */,
false /* showSpinner */, null /* mimeType */, null /* uri */);
}
@VisibleForTesting
StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry,
StatusBarNotification rebuildNotificationWithRemoteInputInserted(NotificationEntry entry,
CharSequence remoteInputText, boolean showSpinner, String mimeType, Uri uri) {
StatusBarNotification sbn = entry.getSbn();
@@ -746,7 +746,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
String remoteInputMimeType = entry.remoteInputMimeType;
Uri remoteInputUri = entry.remoteInputUri;
StatusBarNotification newSbn = rebuildNotificationWithRemoteInput(entry,
StatusBarNotification newSbn = rebuildNotificationWithRemoteInputInserted(entry,
remoteInputText, false /* showSpinner */, remoteInputMimeType,
remoteInputUri);
entry.onRemoteInputInserted();

View File

@@ -51,6 +51,7 @@ import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.view.ContentInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -126,8 +127,12 @@ public final class NotificationEntry extends ListEntry {
public int targetSdk;
private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
public CharSequence remoteInputText;
// Mimetype and Uri used to display the image in the notification *after* it has been sent.
public String remoteInputMimeType;
public Uri remoteInputUri;
// ContentInfo used to keep the attachment permission alive until RemoteInput is sent or
// cancelled.
public ContentInfo remoteInputAttachment;
private Notification.BubbleMetadata mBubbleMetadata;
private ShortcutInfo mShortcutInfo;

View File

@@ -20,7 +20,6 @@ import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -38,7 +37,6 @@ import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.Editable;
@@ -72,13 +70,13 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -111,8 +109,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private final SendButtonTextWatcher mTextWatcher;
private final TextView.OnEditorActionListener mEditorActionHandler;
private final NotificationRemoteInputManager mRemoteInputManager;
private final UiEventLogger mUiEventLogger;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final List<OnFocusChangeListener> mEditTextFocusChangeListeners = new ArrayList<>();
private final List<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
private RemoteEditText mEditText;
@@ -123,9 +121,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private RemoteInput[] mRemoteInputs;
private RemoteInput mRemoteInput;
private RemoteInputController mController;
private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private IStatusBarService mStatusBarManagerService;
private NotificationEntry mEntry;
@@ -134,7 +129,6 @@ 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;
@@ -143,7 +137,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private NotificationViewWrapper mWrapper;
private Consumer<Boolean> mOnVisibilityChangedListener;
private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
private LinearLayout mContentView;
private ImageView mDelete;
private ImageView mDeleteBg;
@@ -174,10 +167,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mTextWatcher = new SendButtonTextWatcher();
mEditorActionHandler = new EditorActionHandler();
mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
mUiEventLogger = Dependency.get(UiEventLogger.class);
mStatusBarManagerService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
com.android.internal.R.attr.colorAccent,
com.android.internal.R.attr.colorSurface,
@@ -266,8 +256,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
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);
LinearLayout contentView = findViewById(R.id.remote_input_content);
contentView.setBackground(mContentBackground);
mEditText = findViewById(R.id.remote_input_text);
mEditText.setInnerFocusable(false);
mEditText.setWindowInsetsAnimationCallback(
@@ -293,15 +283,19 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
private void setAttachment(ContentInfo item) {
if (mAttachment != null) {
if (mEntry.remoteInputAttachment != null && mEntry.remoteInputAttachment != item) {
// 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();
mEntry.remoteInputAttachment.releasePermissions();
}
mEntry.remoteInputAttachment = item;
if (item != null) {
mEntry.remoteInputUri = item.getClip().getItemAt(0).getUri();
mEntry.remoteInputMimeType = item.getClip().getDescription().getMimeType(0);
}
mAttachment = item;
View attachment = findViewById(R.id.remote_input_content_container);
ImageView iconView = findViewById(R.id.remote_input_attachment_image);
iconView.setImageDrawable(null);
@@ -323,10 +317,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
* @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());
return mEntry.remoteInputAttachment == null
? prepareRemoteInputFromText()
: prepareRemoteInputFromData(mEntry.remoteInputMimeType, mEntry.remoteInputUri);
}
private Intent prepareRemoteInputFromText() {
@@ -337,7 +330,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
results);
mEntry.remoteInputText = mEditText.getText().toString();
// TODO(b/188646667): store attachment to entry
setAttachment(null);
mEntry.remoteInputUri = null;
mEntry.remoteInputMimeType = null;
@@ -363,7 +356,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
bundle);
CharSequence attachmentText = mAttachment.getClip().getDescription().getLabel();
CharSequence attachmentText =
mEntry.remoteInputAttachment.getClip().getDescription().getLabel();
CharSequence attachmentLabel = TextUtils.isEmpty(attachmentText)
? mContext.getString(R.string.remote_input_image_insertion_text)
@@ -374,14 +368,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
: "\"" + attachmentLabel + "\" " + mEditText.getText();
mEntry.remoteInputText = fullText;
// TODO(b/188646667): store attachment to entry
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) {
} else if (mEntry.remoteInputAttachment == null) {
RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE);
}
@@ -437,6 +428,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
mEntry.getSbn().getInstanceId());
}
setAttachment(null);
}
@@ -477,7 +469,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private void onDefocus(boolean animate, boolean logClose) {
mController.removeRemoteInput(mEntry, mToken);
mEntry.remoteInputText = mEditText.getText();
// TODO(b/188646667): store attachment to entry
// During removal, we get reattached and lose focus. Not hiding in that
// case to prevent flicker.
@@ -565,7 +556,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mEntry.editedSuggestionInfo = editedSuggestionInfo;
if (editedSuggestionInfo != null) {
mEntry.remoteInputText = editedSuggestionInfo.originalText;
// TODO(b/188646667): store attachment to entry
mEntry.remoteInputAttachment = null;
}
}
@@ -608,7 +599,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mEditText.setSelection(mEditText.length());
mEditText.requestFocus();
mController.addRemoteInput(mEntry, mToken);
// TODO(b/188646667): restore attachment from entry
setAttachment(mEntry.remoteInputAttachment);
mRemoteInputQuickSettingsDisabler.setRemoteInputActive(true);
@@ -631,7 +622,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private void reset() {
mResetting = true;
mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
// TODO(b/188646667): store attachment at time of reset to entry
mEditText.getText().clear();
mEditText.setEnabled(true);
@@ -640,7 +630,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mController.removeSpinning(mEntry.getKey(), mToken);
updateSendButton();
onDefocus(false /* animate */, false /* logClose */);
// TODO(b/188646667): clear attachment
setAttachment(null);
mResetting = false;
}
@@ -657,7 +647,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
private void updateSendButton() {
mSendButton.setEnabled(mEditText.length() != 0 || mAttachment != null);
mSendButton.setEnabled(mEditText.length() != 0 || mEntry.remoteInputAttachment != null);
}
public void close() {
@@ -857,7 +847,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
&& event.getAction() == KeyEvent.ACTION_DOWN;
if (isSoftImeEvent || isKeyboardEnterKey) {
if (mEditText.length() > 0 || mAttachment != null) {
if (mEditText.length() > 0 || mEntry.remoteInputAttachment != null) {
sendRemoteInput(prepareRemoteInput());
}
// Consume action to prevent IME from closing.
@@ -928,7 +918,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
// our focus, so we'll need to save our text here.
if (mRemoteInputView != null) {
mRemoteInputView.mEntry.remoteInputText = getText();
// TODO(b/188646667): store attachment to entry
}
}
return;

View File

@@ -161,7 +161,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
String mimeType = "image/jpeg";
String text = "image inserted";
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
mEntry, text, false, mimeType, uri);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
@@ -174,7 +174,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
@Test
public void testRebuildWithRemoteInput_noExistingInputNoSpinner() {
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
mEntry, "A Reply", false, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
@@ -189,7 +189,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
@Test
public void testRebuildWithRemoteInput_noExistingInputWithSpinner() {
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
mEntry, "A Reply", true, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
@@ -205,14 +205,14 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
public void testRebuildWithRemoteInput_withExistingInput() {
// Setup a notification entry with 1 remote input.
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
mEntry, "A Reply", false, null, null);
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(newSbn)
.build();
// Try rebuilding to add another reply.
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
entry, "Reply 2", true, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
@@ -228,14 +228,14 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
String mimeType = "image/jpeg";
String text = "image inserted";
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(
mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
mEntry, text, false, mimeType, uri);
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(newSbn)
.build();
// Try rebuilding to add another reply.
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
entry, "Reply 2", true, null, null);
RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
.extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);