Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57eb5363 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Persist remote input image attachment across layouts" into sc-dev am: 931584a9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15128149

Change-Id: I179c2b1a6a6309a5a5743219100034573cf1b997
parents bda27d11 931584a9
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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();
+5 −0
Original line number Diff line number Diff line
@@ -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;

+24 −35
Original line number Diff line number Diff line
@@ -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;
+7 −7
Original line number Diff line number Diff line
@@ -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);