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

Commit c4035ef3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Show RemoteInput images in notification history."

parents 1e172bf5 2e3cc416
Loading
Loading
Loading
Loading
+67 −16
Original line number Diff line number Diff line
@@ -1004,6 +1004,31 @@ public class Notification implements Parcelable
     */
    public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";


    /**
     * {@link #extras} key: this is a remote input history which can include media messages
     * in addition to text, as supplied to
     * {@link Builder#setRemoteInputHistory(RemoteInputHistoryItem[])} or
     * {@link Builder#setRemoteInputHistory(CharSequence[])}.
     *
     * SystemUI can populate this through
     * {@link Builder#setRemoteInputHistory(RemoteInputHistoryItem[])} with the most recent inputs
     * that have been sent through a {@link RemoteInput} of this Notification. These items can
     * represent either media content (specified by a URI and a MIME type) or a text message
     * (described by a CharSequence).
     *
     * To maintain compatibility, this can also be set by apps with
     * {@link Builder#setRemoteInputHistory(CharSequence[])}, which will create a
     * {@link RemoteInputHistoryItem} for each of the provided text-only messages.
     *
     * The extra with this key is of type {@link RemoteInputHistoryItem[]} and contains the most
     * recent entry at the 0 index, the second most recent at the 1 index, etc.
     *
     * @see Builder#setRemoteInputHistory(RemoteInputHistoryItem[])
     * @hide
     */
    public static final String EXTRA_REMOTE_INPUT_HISTORY_ITEMS = "android.remoteInputHistoryItems";

    /**
     * {@link #extras} key: boolean as supplied to
     * {@link Builder#setShowRemoteInputSpinner(boolean)}.
@@ -3833,12 +3858,37 @@ public class Notification implements Parcelable
            if (text == null) {
                mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, null);
            } else {
                final int N = Math.min(MAX_REPLY_HISTORY, text.length);
                CharSequence[] safe = new CharSequence[N];
                for (int i = 0; i < N; i++) {
                final int itemCount = Math.min(MAX_REPLY_HISTORY, text.length);
                CharSequence[] safe = new CharSequence[itemCount];
                RemoteInputHistoryItem[] items = new RemoteInputHistoryItem[itemCount];
                for (int i = 0; i < itemCount; i++) {
                    safe[i] = safeCharSequence(text[i]);
                    items[i] = new RemoteInputHistoryItem(text[i]);
                }
                mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, safe);

                // Also add these messages as structured history items.
                mN.extras.putParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS, items);
            }
            return this;
        }

        /**
         * Set the remote input history, with support for embedding URIs and mime types for
         * images and other media.
         * @hide
         */
        @NonNull
        public Builder setRemoteInputHistory(RemoteInputHistoryItem[] items) {
            if (items == null) {
                mN.extras.putParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS, null);
            } else {
                final int itemCount = Math.min(MAX_REPLY_HISTORY, items.length);
                RemoteInputHistoryItem[] history = new RemoteInputHistoryItem[itemCount];
                for (int i = 0; i < itemCount; i++) {
                    history[i] = items[i];
                }
                mN.extras.putParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS, history);
            }
            return this;
        }
@@ -5246,16 +5296,17 @@ public class Notification implements Parcelable
                big.setViewVisibility(R.id.actions_container, View.GONE);
            }

            CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
            if (validRemoteInput && replyText != null
                    && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])
            RemoteInputHistoryItem[] replyText = (RemoteInputHistoryItem[])
                    mN.extras.getParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
            if (validRemoteInput && replyText != null && replyText.length > 0
                    && !TextUtils.isEmpty(replyText[0].getText())
                    && p.maxRemoteInputHistory > 0) {
                boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER);
                big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
                big.setViewVisibility(R.id.notification_material_reply_text_1_container,
                        View.VISIBLE);
                big.setTextViewText(R.id.notification_material_reply_text_1,
                        processTextSpans(replyText[0]));
                        processTextSpans(replyText[0].getText()));
                setTextViewColorSecondary(big, R.id.notification_material_reply_text_1, p);
                big.setViewVisibility(R.id.notification_material_reply_progress,
                        showSpinner ? View.VISIBLE : View.GONE);
@@ -5264,19 +5315,19 @@ public class Notification implements Parcelable
                        ColorStateList.valueOf(
                                isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p)));

                if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])
                if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText())
                        && p.maxRemoteInputHistory > 1) {
                    big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
                    big.setTextViewText(R.id.notification_material_reply_text_2,
                            processTextSpans(replyText[1]));
                            processTextSpans(replyText[1].getText()));
                    setTextViewColorSecondary(big, R.id.notification_material_reply_text_2, p);

                    if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])
                    if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2].getText())
                            && p.maxRemoteInputHistory > 2) {
                        big.setViewVisibility(
                                R.id.notification_material_reply_text_3, View.VISIBLE);
                        big.setTextViewText(R.id.notification_material_reply_text_3,
                                processTextSpans(replyText[2]));
                                processTextSpans(replyText[2].getText()));
                        setTextViewColorSecondary(big, R.id.notification_material_reply_text_3, p);
                    }
                }
@@ -7517,7 +7568,7 @@ public class Notification implements Parcelable
            @Nullable
            private final Person mSender;
            /** True if this message was generated from the extra
             *  {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}
             *  {@link Notification#EXTRA_REMOTE_INPUT_HISTORY_ITEMS}
             */
            private final boolean mRemoteInputHistory;

@@ -7569,7 +7620,7 @@ public class Notification implements Parcelable
             * Should be <code>null</code> for messages by the current user, in which case
             * the platform will insert the user set in {@code MessagingStyle(Person)}.
             * @param remoteInputHistory True if the messages was generated from the extra
             * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}.
             * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY_ITEMS}.
             * <p>
             * The person provided should contain an Icon, set with
             * {@link Person.Builder#setIcon(Icon)} and also have a name provided
@@ -7676,7 +7727,7 @@ public class Notification implements Parcelable

            /**
             * @return True if the message was generated from
             * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}.
             * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY_ITEMS}.
             * @hide
             */
            public boolean isRemoteInputHistory() {
@@ -7906,8 +7957,8 @@ public class Notification implements Parcelable
            if (mBuilder.mActions.size() > 0) {
                maxRows--;
            }
            CharSequence[] remoteInputHistory = mBuilder.mN.extras.getCharSequenceArray(
                    EXTRA_REMOTE_INPUT_HISTORY);
            RemoteInputHistoryItem[] remoteInputHistory = (RemoteInputHistoryItem[])
                    mBuilder.mN.extras.getParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
            if (remoteInputHistory != null
                    && remoteInputHistory.length > NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION) {
                // Let's remove some messages to make room for the remote input history.
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * Stores historical input from a RemoteInput attached to a Notification.
 *
 * History items represent either a text message (specified by providing a CharSequence,
 * or a media message (specified by providing a URI and a MIME type). Media messages must also
 * include text to insert when the image cannot be loaded, ex. when URI read permission has not been
 * granted correctly.
 *
 * @hide
 */
public class RemoteInputHistoryItem implements Parcelable {
    private CharSequence mText;
    private String mMimeType;
    private Uri mUri;

    public RemoteInputHistoryItem(String mimeType, Uri uri, CharSequence backupText) {
        this.mMimeType = mimeType;
        this.mUri = uri;
        this.mText = Notification.safeCharSequence(backupText);
    }

    public RemoteInputHistoryItem(CharSequence text) {
        this.mText = Notification.safeCharSequence(text);
    }

    protected RemoteInputHistoryItem(Parcel in) {
        mText = in.readCharSequence();
        mMimeType = in.readStringNoHelper();
        mUri = in.readParcelable(Uri.class.getClassLoader());
    }

    public static final Creator<RemoteInputHistoryItem> CREATOR =
            new Creator<RemoteInputHistoryItem>() {
                @Override
                public RemoteInputHistoryItem createFromParcel(Parcel in) {
                    return new RemoteInputHistoryItem(in);
                }

                @Override
                public RemoteInputHistoryItem[] newArray(int size) {
                    return new RemoteInputHistoryItem[size];
                }
            };

    public CharSequence getText() {
        return mText;
    }

    public String getMimeType() {
        return mMimeType;
    }

    public Uri getUri() {
        return mUri;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeCharSequence(mText);
        dest.writeStringNoHelper(mMimeType);
        dest.writeParcelable(mUri, flags);
    }
}
+12 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.app.Notification;
import android.app.Person;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -161,8 +162,9 @@ public class MessagingLayout extends FrameLayout implements ImageMessageConsumer
        if (headerText != null) {
            mConversationTitle = headerText.getText();
        }
        addRemoteInputHistoryToMessages(newMessages,
                extras.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY));
        RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
                extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
        addRemoteInputHistoryToMessages(newMessages, history);
        boolean showSpinner =
                extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
        bind(newMessages, newHistoricMessages, showSpinner);
@@ -175,14 +177,18 @@ public class MessagingLayout extends FrameLayout implements ImageMessageConsumer

    private void addRemoteInputHistoryToMessages(
            List<Notification.MessagingStyle.Message> newMessages,
            CharSequence[] remoteInputHistory) {
            RemoteInputHistoryItem[] remoteInputHistory) {
        if (remoteInputHistory == null || remoteInputHistory.length == 0) {
            return;
        }
        for (int i = remoteInputHistory.length - 1; i >= 0; i--) {
            CharSequence message = remoteInputHistory[i];
            newMessages.add(new Notification.MessagingStyle.Message(
                    message, 0, (Person) null, true /* remoteHistory */));
            RemoteInputHistoryItem historyMessage = remoteInputHistory[i];
            Notification.MessagingStyle.Message message = new Notification.MessagingStyle.Message(
                    historyMessage.getText(), 0, (Person) null, true /* remoteHistory */);
            if (historyMessage.getUri() != null) {
                message.setData(historyMessage.getMimeType(), historyMessage.getUri());
            }
            newMessages.add(message);
        }
    }

+4 −0
Original line number Diff line number Diff line
@@ -194,6 +194,10 @@
    <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]-->
    <string name="global_action_screenshot">Screenshot</string>

    <!-- text to show in place of RemoteInput images when they cannot be shown.
         [CHAR LIMIT=50] -->
    <string name="remote_input_image_insertion_text">Image inserted</string>

    <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
    <string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
    <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->
+28 −14
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -345,7 +347,8 @@ public class NotificationRemoteInputManager implements Dumpable {
        });
        mSmartReplyController.setCallback((entry, reply) -> {
            StatusBarNotification newSbn =
                    rebuildNotificationWithRemoteInput(entry, reply, true /* showSpinner */);
                    rebuildNotificationWithRemoteInput(entry, reply, true /* showSpinner */,
                            null /* mimeType */, null /* uri */);
            mEntryManager.updateNotification(newSbn, null /* ranking */);
        });
    }
@@ -527,28 +530,36 @@ public class NotificationRemoteInputManager implements Dumpable {
    StatusBarNotification rebuildNotificationForCanceledSmartReplies(
            NotificationEntry entry) {
        return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
                false /* showSpinner */);
                false /* showSpinner */, null /* mimeType */, null /* uri */);
    }

    @VisibleForTesting
    StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry,
            CharSequence remoteInputText, boolean showSpinner) {
            CharSequence remoteInputText, boolean showSpinner, String mimeType, Uri uri) {
        StatusBarNotification sbn = entry.getSbn();

        Notification.Builder b = Notification.Builder
                .recoverBuilder(mContext, sbn.getNotification().clone());
        if (remoteInputText != null) {
            CharSequence[] oldHistory = sbn.getNotification().extras
                    .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
            CharSequence[] newHistory;
            if (oldHistory == null) {
                newHistory = new CharSequence[1];
        if (remoteInputText != null || uri != null) {
            RemoteInputHistoryItem[] oldHistoryItems = (RemoteInputHistoryItem[])
                    sbn.getNotification().extras.getParcelableArray(
                            Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
            RemoteInputHistoryItem[] newHistoryItems;

            if (oldHistoryItems == null) {
                newHistoryItems = new RemoteInputHistoryItem[1];
            } else {
                newHistory = new CharSequence[oldHistory.length + 1];
                System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
                newHistoryItems = new RemoteInputHistoryItem[oldHistoryItems.length + 1];
                System.arraycopy(oldHistoryItems, 0, newHistoryItems, 1, oldHistoryItems.length);
            }
            newHistory[0] = String.valueOf(remoteInputText);
            b.setRemoteInputHistory(newHistory);
            RemoteInputHistoryItem newItem;
            if (uri != null) {
                newItem = new RemoteInputHistoryItem(mimeType, uri, remoteInputText);
            } else {
                newItem = new RemoteInputHistoryItem(remoteInputText);
            }
            newHistoryItems[0] = newItem;
            b.setRemoteInputHistory(newHistoryItems);
        }
        b.setShowRemoteInputSpinner(showSpinner);
        b.setHideSmartReplies(true);
@@ -631,8 +642,11 @@ public class NotificationRemoteInputManager implements Dumpable {
                if (TextUtils.isEmpty(remoteInputText)) {
                    remoteInputText = entry.remoteInputTextWhenReset;
                }
                String remoteInputMimeType = entry.remoteInputMimeType;
                Uri remoteInputUri = entry.remoteInputUri;
                StatusBarNotification newSbn = rebuildNotificationWithRemoteInput(entry,
                        remoteInputText, false /* showSpinner */);
                        remoteInputText, false /* showSpinner */, remoteInputMimeType,
                        remoteInputUri);
                entry.onRemoteInputInserted();

                if (newSbn == null) {
Loading