Merge "Fixes for SyncRtSurfaceTransactionApplier" into pi-dev
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0a667cc..a59c0f4 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -164,6 +164,7 @@
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
Landroid/app/ActivityManager;->setPersistentVrThread(I)V
Landroid/app/ActivityManager;->staticGetMemoryClass()I
+Landroid/app/ActivityManager;->switchUser(I)Z
Landroid/app/ActivityManagerNative;-><init>()V
Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
@@ -572,6 +573,7 @@
Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V
Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
Landroid/app/IActivityManager;->broadcastIntent(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;Landroid/content/IIntentReceiver;ILjava/lang/String;Landroid/os/Bundle;[Ljava/lang/String;ILandroid/os/Bundle;ZZI)I
@@ -895,6 +897,9 @@
Landroid/app/SearchManager;->launchAssist(Landroid/os/Bundle;)V
Landroid/app/SearchManager;->mSearchDialog:Landroid/app/SearchDialog;
Landroid/app/SearchManager;->startSearch(Ljava/lang/String;ZLandroid/content/ComponentName;Landroid/os/Bundle;ZLandroid/graphics/Rect;)V
+Landroid/app/servertransaction/ClientTransaction;->mActivityCallbacks:Ljava/util/List;
+Landroid/app/servertransaction/LaunchActivityItem;->mInfo:Landroid/content/pm/ActivityInfo;
+Landroid/app/servertransaction/LaunchActivityItem;->mIntent:Landroid/content/Intent;
Landroid/app/Service;->attach(Landroid/content/Context;Landroid/app/ActivityThread;Ljava/lang/String;Landroid/os/IBinder;Landroid/app/Application;Ljava/lang/Object;)V
Landroid/app/Service;->mActivityManager:Landroid/app/IActivityManager;
Landroid/app/Service;->mApplication:Landroid/app/Application;
@@ -2203,6 +2208,7 @@
Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
Landroid/graphics/GraphicBuffer;->mNativeObject:J
Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
+Landroid/graphics/ImageFormat;->Y8:I
Landroid/graphics/Insets;->bottom:I
Landroid/graphics/Insets;->left:I
Landroid/graphics/Insets;->NONE:Landroid/graphics/Insets;
@@ -4211,6 +4217,7 @@
Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
Landroid/os/UEventObserver;-><init>()V
+Landroid/os/UEventObserver;->onUEvent(Landroid/os/UEventObserver$UEvent;)V
Landroid/os/UEventObserver;->startObserving(Ljava/lang/String;)V
Landroid/os/UEventObserver;->stopObserving()V
Landroid/os/UpdateLock;->acquire()V
@@ -4439,9 +4446,11 @@
Landroid/provider/Downloads$Impl;->isStatusSuccess(I)Z
Landroid/provider/Downloads$Impl;->PUBLICLY_ACCESSIBLE_DOWNLOADS_URI:Landroid/net/Uri;
Landroid/provider/MediaStore$Files$FileColumns;->FORMAT:Ljava/lang/String;
+Landroid/provider/MediaStore$Files$FileColumns;->STORAGE_ID:Ljava/lang/String;
Landroid/provider/MediaStore$Files;->getMtpObjectsUri(Ljava/lang/String;)Landroid/net/Uri;
Landroid/provider/MediaStore$Files;->getMtpObjectsUri(Ljava/lang/String;J)Landroid/net/Uri;
Landroid/provider/MediaStore$Files;->getMtpReferencesUri(Ljava/lang/String;J)Landroid/net/Uri;
+Landroid/provider/MediaStore$MediaColumns;->IS_DRM:Ljava/lang/String;
Landroid/provider/Settings$Bookmarks;->add(Landroid/content/ContentResolver;Landroid/content/Intent;Ljava/lang/String;Ljava/lang/String;CI)Landroid/net/Uri;
Landroid/provider/Settings$Bookmarks;->CONTENT_URI:Landroid/net/Uri;
Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
@@ -4484,6 +4493,7 @@
Landroid/provider/Settings$Secure;->ENABLED_PRINT_SERVICES:Ljava/lang/String;
Landroid/provider/Settings$Secure;->getIntForUser(Landroid/content/ContentResolver;Ljava/lang/String;II)I
Landroid/provider/Settings$Secure;->getLongForUser(Landroid/content/ContentResolver;Ljava/lang/String;JI)J
+Landroid/provider/Settings$Secure;->IMMERSIVE_MODE_CONFIRMATIONS:Ljava/lang/String;
Landroid/provider/Settings$Secure;->INCALL_POWER_BUTTON_BEHAVIOR:Ljava/lang/String;
Landroid/provider/Settings$Secure;->LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS:Ljava/lang/String;
Landroid/provider/Settings$Secure;->LOCK_SCREEN_LOCK_AFTER_TIMEOUT:Ljava/lang/String;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 526888d..a591eaf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -984,6 +984,17 @@
public static final String EXTRA_SHOW_REMOTE_INPUT_SPINNER = "android.remoteInputSpinner";
/**
+ * {@link #extras} key: boolean as supplied to
+ * {@link Builder#setHideSmartReplies(boolean)}.
+ *
+ * If set to true, then any smart reply buttons will be hidden.
+ *
+ * @see Builder#setHideSmartReplies(boolean)
+ * @hide
+ */
+ public static final String EXTRA_HIDE_SMART_REPLIES = "android.hideSmartReplies";
+
+ /**
* {@link #extras} key: this is a small piece of additional text as supplied to
* {@link Builder#setContentInfo(CharSequence)}.
*/
@@ -3595,6 +3606,15 @@
}
/**
+ * Sets whether smart reply buttons should be hidden.
+ * @hide
+ */
+ public Builder setHideSmartReplies(boolean hideSmartReplies) {
+ mN.extras.putBoolean(EXTRA_HIDE_SMART_REPLIES, hideSmartReplies);
+ return this;
+ }
+
+ /**
* Sets the number of items this notification represents. May be displayed as a badge count
* for Launchers that support badging.
*/
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1f00c78..02bf4e3 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1584,6 +1584,20 @@
*/
public static final int BUFFER_FLAG_PARTIAL_FRAME = 8;
+ /**
+ * This indicates that the buffer contains non-media data for the
+ * muxer to process.
+ *
+ * All muxer data should start with a FOURCC header that determines the type of data.
+ *
+ * For example, when it contains Exif data sent to a MediaMuxer track of
+ * {@link MediaFormat#MIMETYPE_IMAGE_ANDROID_HEIC} type, the data must start with
+ * Exif header ("Exif\0\0"), followed by the TIFF header (See JEITA CP-3451C Section 4.5.2.)
+ *
+ * @hide
+ */
+ public static final int BUFFER_FLAG_MUXER_DATA = 16;
+
/** @hide */
@IntDef(
flag = true,
@@ -1593,6 +1607,7 @@
BUFFER_FLAG_CODEC_CONFIG,
BUFFER_FLAG_END_OF_STREAM,
BUFFER_FLAG_PARTIAL_FRAME,
+ BUFFER_FLAG_MUXER_DATA,
})
@Retention(RetentionPolicy.SOURCE)
public @interface BufferFlag {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 724bd22..952c961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -1384,6 +1384,13 @@
smartReplyContainer.setVisibility(View.GONE);
return null;
}
+ // If we are keeping the notification around while sending we don't want to add the buttons.
+ boolean hideSmartReplies = entry.notification.getNotification()
+ .extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false);
+ if (hideSmartReplies) {
+ smartReplyContainer.setVisibility(View.GONE);
+ return null;
+ }
SmartReplyView smartReplyView = null;
if (smartReplyContainer.getChildCount() == 0) {
smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index f14ca71..30fa0c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -113,6 +113,8 @@
Dependency.get(ForegroundServiceController.class);
protected final NotificationListener mNotificationListener =
Dependency.get(NotificationListener.class);
+ private final SmartReplyController mSmartReplyController =
+ Dependency.get(SmartReplyController.class);
protected IStatusBarService mBarService;
protected NotificationPresenter mPresenter;
@@ -127,6 +129,13 @@
protected boolean mDisableNotificationAlerts;
protected NotificationListContainer mListContainer;
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them around
+ * when they were canceled in response to a remote input interaction. This allows us to show
+ * what you replied and allows you to continue typing into it.
+ */
+ private final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
private final class NotificationClicker implements View.OnClickListener {
@@ -220,6 +229,8 @@
}
pw.print(" mUseHeadsUp=");
pw.println(mUseHeadsUp);
+ pw.print(" mKeysKeptForRemoteInput: ");
+ pw.println(mKeysKeptForRemoteInput);
}
public NotificationEntryManager(Context context) {
@@ -374,6 +385,12 @@
final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count,
true);
NotificationData.Entry entry = mNotificationData.get(n.getKey());
+
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
+
mRemoteInputManager.onPerformRemoveNotification(n, entry);
final String pkg = n.getPackageName();
final String tag = n.getTag();
@@ -491,10 +508,35 @@
}
if (updated) {
Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key);
- mRemoteInputManager.getKeysKeptForRemoteInput().add(entry.key);
+ addKeyKeptForRemoteInput(entry.key);
return;
}
}
+
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && shouldKeepForSmartReply(entry)
+ && entry.row != null && !entry.row.isDismissed()) {
+ // Turn off the spinner and hide buttons when an app cancels the notification.
+ StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
+ boolean updated = false;
+ try {
+ updateNotificationInternal(newSbn, null);
+ updated = true;
+ } catch (InflationException e) {
+ // Ignore just don't keep the notification around.
+ }
+ // Treat the reply as longer sending.
+ mSmartReplyController.stopSending(entry);
+ if (updated) {
+ Log.w(TAG, "Keeping notification around after sending smart reply " + entry.key);
+ addKeyKeptForRemoteInput(entry.key);
+ return;
+ }
+ }
+
+ // Actually removing notification so smart reply controller can forget about it.
+ mSmartReplyController.stopSending(entry);
+
if (deferRemoval) {
mLatestRankingMap = ranking;
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -536,18 +578,21 @@
Notification.Builder b = Notification.Builder
.recoverBuilder(mContext, sbn.getNotification().clone());
- CharSequence[] oldHistory = sbn.getNotification().extras
- .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
- CharSequence[] newHistory;
- if (oldHistory == null) {
- newHistory = new CharSequence[1];
- } else {
- newHistory = new CharSequence[oldHistory.length + 1];
- System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
+ if (remoteInputText != null) {
+ CharSequence[] oldHistory = sbn.getNotification().extras
+ .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ CharSequence[] newHistory;
+ if (oldHistory == null) {
+ newHistory = new CharSequence[1];
+ } else {
+ newHistory = new CharSequence[oldHistory.length + 1];
+ System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
+ }
+ newHistory[0] = String.valueOf(remoteInputText);
+ b.setRemoteInputHistory(newHistory);
}
- newHistory[0] = String.valueOf(remoteInputText);
- b.setRemoteInputHistory(newHistory);
b.setShowRemoteInputSpinner(showSpinner);
+ b.setHideSmartReplies(true);
Notification newNotification = b.build();
@@ -563,6 +608,17 @@
return newSbn;
}
+ @VisibleForTesting
+ StatusBarNotification rebuildNotificationForCanceledSmartReplies(
+ NotificationData.Entry entry) {
+ return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
+ false /* showSpinner */);
+ }
+
+ private boolean shouldKeepForSmartReply(NotificationData.Entry entry) {
+ return entry != null && mSmartReplyController.isSendingSmartReply(entry.key);
+ }
+
private boolean shouldKeepForRemoteInput(NotificationData.Entry entry) {
if (entry == null) {
return false;
@@ -792,6 +848,7 @@
}
mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
mRemoteInputManager.onUpdateNotification(entry);
+ mSmartReplyController.stopSending(entry);
if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) {
mGutsManager.setKeyToRemoveOnGutsClosed(null);
@@ -955,6 +1012,20 @@
return mHeadsUpManager.isHeadsUp(key);
}
+ public boolean isNotificationKeptForRemoteInput(String key) {
+ return mKeysKeptForRemoteInput.contains(key);
+ }
+
+ public void removeKeyKeptForRemoteInput(String key) {
+ mKeysKeptForRemoteInput.remove(key);
+ }
+
+ public void addKeyKeptForRemoteInput(String key) {
+ if (FORCE_REMOTE_INPUT_HISTORY) {
+ mKeysKeptForRemoteInput.add(key);
+ }
+ }
+
/**
* Callback for NotificationEntryManager.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 0144f42..a2d0c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -75,7 +75,7 @@
mPresenter.getHandler().post(() -> {
processForRemoteInput(sbn.getNotification(), mContext);
String key = sbn.getKey();
- mRemoteInputManager.getKeysKeptForRemoteInput().remove(key);
+ mEntryManager.removeKeyKeptForRemoteInput(key);
boolean isUpdate =
mEntryManager.getNotificationData().get(key) != null;
// In case we don't allow child notifications, we ignore children of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index a333654..9e87a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -77,12 +77,6 @@
protected final NotificationLockscreenUserManager mLockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
- /**
- * Notifications with keys in this set are not actually around anymore. We kept them around
- * when they were canceled in response to a remote input interaction. This allows us to show
- * what you replied and allows you to continue typing into it.
- */
- protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
protected final Context mContext;
private final UserManager mUserManager;
@@ -290,7 +284,8 @@
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
public void onRemoteInputSent(NotificationData.Entry entry) {
- if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mEntryManager.isNotificationKeptForRemoteInput(entry.key)) {
mEntryManager.removeNotification(entry.key, null);
} else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
// We're currently holding onto this notification, but from the apps point of
@@ -340,10 +335,6 @@
if (mRemoteInputController.isRemoteInputActive(entry)) {
mRemoteInputController.removeRemoteInput(entry, null);
}
- if (FORCE_REMOTE_INPUT_HISTORY
- && mKeysKeptForRemoteInput.contains(n.getKey())) {
- mKeysKeptForRemoteInput.remove(n.getKey());
- }
}
public void removeRemoteInputEntriesKeptUntilCollapsed() {
@@ -368,8 +359,6 @@
pw.println("NotificationRemoteInputManager state:");
pw.print(" mRemoteInputEntriesToRemoveOnCollapse: ");
pw.println(mRemoteInputEntriesToRemoveOnCollapse);
- pw.print(" mKeysKeptForRemoteInput: ");
- pw.println(mKeysKeptForRemoteInput);
}
public void bindRow(ExpandableNotificationRow row) {
@@ -377,10 +366,6 @@
row.setRemoteViewClickHandler(mOnClickHandler);
}
- public Set<String> getKeysKeptForRemoteInput() {
- return mKeysKeptForRemoteInput;
- }
-
@VisibleForTesting
public Set<NotificationData.Entry> getRemoteInputEntriesToRemoveOnCollapse() {
return mRemoteInputEntriesToRemoveOnCollapse;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 67da68c..5ba75de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -17,10 +17,12 @@
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
+import java.util.Set;
/**
* Handles when smart replies are added to a notification
@@ -28,18 +30,20 @@
*/
public class SmartReplyController {
private IStatusBarService mBarService;
- private NotificationEntryManager mNotificationEntryManager;
+ private Set<String> mSendingKeys = new ArraySet<>();
public SmartReplyController() {
mBarService = Dependency.get(IStatusBarService.class);
- mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
}
public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply) {
+ NotificationEntryManager notificationEntryManager
+ = Dependency.get(NotificationEntryManager.class);
StatusBarNotification newSbn =
- mNotificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply,
+ notificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply,
true /* showSpinner */);
- mNotificationEntryManager.updateNotification(newSbn, null /* ranking */);
+ notificationEntryManager.updateNotification(newSbn, null /* ranking */);
+ mSendingKeys.add(entry.key);
try {
mBarService.onNotificationSmartReplySent(entry.notification.getKey(),
@@ -49,6 +53,14 @@
}
}
+ /**
+ * Have we posted an intent to an app about sending a smart reply from the
+ * notification with this key.
+ */
+ public boolean isSendingSmartReply(String key) {
+ return mSendingKeys.contains(key);
+ }
+
public void smartRepliesAdded(final NotificationData.Entry entry, int replyCount) {
try {
mBarService.onNotificationSmartRepliesAdded(entry.notification.getKey(),
@@ -57,4 +69,10 @@
// Nothing to do, system going down
}
}
+
+ public void stopSending(final NotificationData.Entry entry) {
+ if (entry != null) {
+ mSendingKeys.remove(entry.notification.getKey());
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index ee83250..f7b7eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -165,7 +165,9 @@
showNotificationIconArea(animate);
}
}
- if ((diff1 & DISABLE_CLOCK) != 0) {
+ // The clock may have already been hidden, but we might want to shift its
+ // visibility to GONE from INVISIBLE or vice versa
+ if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
if ((state1 & DISABLE_CLOCK) != 0) {
hideClock(animate);
} else {
@@ -212,13 +214,24 @@
}
public void hideClock(boolean animate) {
- animateHiddenState(mClockView, View.GONE, animate);
+ animateHiddenState(mClockView, clockHiddenMode(), animate);
}
public void showClock(boolean animate) {
animateShow(mClockView, animate);
}
+ /**
+ * If panel is expanded/expanding it usually means QS shade is opening, so
+ * don't set the clock GONE otherwise it'll mess up the animation.
+ */
+ private int clockHiddenMode() {
+ if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()) {
+ return View.INVISIBLE;
+ }
+ return View.GONE;
+ }
+
public void hideNotificationIconArea(boolean animate) {
animateHide(mNotificationIconAreaInner, animate);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index d5d87cc..2a1db4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5161,8 +5161,7 @@
removeNotification(parentToCancelFinal);
}
if (shouldAutoCancel(sbn)
- || mRemoteInputManager.getKeysKeptForRemoteInput().contains(
- notificationKey)) {
+ || mEntryManager.isNotificationKeptForRemoteInput(notificationKey)) {
// Automatically remove all notifications that we may have kept around longer
removeNotification(sbn);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index cc802a8..585787e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -207,6 +207,7 @@
b.setText(choice);
OnDismissAction action = () -> {
+ smartReplyController.smartReplySent(entry, replyIndex, b.getText());
Bundle results = new Bundle();
results.putString(remoteInput.getResultKey(), choice.toString());
Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -217,7 +218,6 @@
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Unable to send smart reply", e);
}
- smartReplyController.smartReplySent(entry, replyIndex, b.getText());
mSmartReplyContainer.setVisibility(View.GONE);
return false; // do not defer
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index f05cf6b..afe16cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -19,6 +19,7 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -97,6 +98,7 @@
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private MetricsLogger mMetricsLogger;
+ @Mock private SmartReplyController mSmartReplyController;
private NotificationData.Entry mEntry;
private StatusBarNotification mSbn;
@@ -158,6 +160,7 @@
mDeviceProvisionedController);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+ mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
mCountDownLatch = new CountDownLatch(1);
@@ -262,6 +265,7 @@
verify(mMediaManager).onNotificationRemoved(mSbn.getKey());
verify(mRemoteInputManager).onRemoveNotification(mEntry);
+ verify(mSmartReplyController).stopSending(mEntry);
verify(mForegroundServiceController).removeNotification(mSbn);
verify(mListContainer).cleanUpViewState(mRow);
verify(mPresenter).updateNotificationViews();
@@ -272,6 +276,20 @@
}
@Test
+ public void testRemoveNotification_blockedBySendingSmartReply() throws Exception {
+ com.android.systemui.util.Assert.isNotMainThread();
+
+ mEntry.row = mRow;
+ mEntryManager.getNotificationData().add(mEntry);
+ when(mSmartReplyController.isSendingSmartReply(mEntry.key)).thenReturn(true);
+
+ mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
+
+ assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+ assertTrue(mEntryManager.isNotificationKeptForRemoteInput(mEntry.key));
+ }
+
+ @Test
public void testUpdateAppOps_foregroundNoti() {
com.android.systemui.util.Assert.isNotMainThread();
@@ -365,6 +383,8 @@
Assert.assertEquals("A Reply", messages[0]);
Assert.assertFalse(newSbn.getNotification().extras
.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ Assert.assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
}
@Test
@@ -377,6 +397,8 @@
Assert.assertEquals("A Reply", messages[0]);
Assert.assertTrue(newSbn.getNotification().extras
.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ Assert.assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
}
@Test
@@ -394,4 +416,15 @@
Assert.assertEquals("Reply 2", messages[0]);
Assert.assertEquals("A Reply", messages[1]);
}
+
+ @Test
+ public void testRebuildNotificationForCanceledSmartReplies() {
+ // Try rebuilding to remove spinner and hide buttons.
+ StatusBarNotification newSbn =
+ mEntryManager.rebuildNotificationForCanceledSmartReplies(mEntry);
+ Assert.assertFalse(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ Assert.assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index c6397e6..26f91b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -60,7 +60,6 @@
private NotificationListener mListener;
private StatusBarNotification mSbn;
- private Set<String> mKeysKeptForRemoteInput;
@Before
public void setUp() {
@@ -69,11 +68,8 @@
mDependency.injectTestDependency(NotificationRemoteInputManager.class,
mRemoteInputManager);
- mKeysKeptForRemoteInput = new HashSet<>();
-
when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
- when(mRemoteInputManager.getKeysKeptForRemoteInput()).thenReturn(mKeysKeptForRemoteInput);
mListener = new NotificationListener(mContext);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
@@ -91,10 +87,9 @@
@Test
public void testPostNotificationRemovesKeyKeptForRemoteInput() {
- mKeysKeptForRemoteInput.add(mSbn.getKey());
mListener.onNotificationPosted(mSbn, mRanking);
TestableLooper.get(this).processAllMessages();
- assertTrue(mKeysKeptForRemoteInput.isEmpty());
+ verify(mEntryManager).removeKeyKeptForRemoteInput(mSbn.getKey());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 8b2f6cd..7a2cb3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -86,11 +86,9 @@
@Test
public void testPerformOnRemoveNotification() {
when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
- mRemoteInputManager.getKeysKeptForRemoteInput().add(mEntry.key);
mRemoteInputManager.onPerformRemoveNotification(mSbn, mEntry);
verify(mController).removeRemoteInput(mEntry, null);
- assertTrue(mRemoteInputManager.getKeysKeptForRemoteInput().isEmpty());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 84dceae..e91530d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -74,7 +76,7 @@
}
@Test
- public void testSendSmartReply_updatesRemoteInput() throws RemoteException {
+ public void testSendSmartReply_updatesRemoteInput() {
StatusBarNotification sbn = mock(StatusBarNotification.class);
when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
when(mNotificationEntryManager.rebuildNotificationWithRemoteInput(
@@ -118,4 +120,21 @@
verify(mIStatusBarService).onNotificationSmartRepliesAdded(TEST_NOTIFICATION_KEY,
TEST_CHOICE_COUNT);
}
+
+ @Test
+ public void testSendSmartReply_reportsSending() {
+ SmartReplyController controller = new SmartReplyController();
+ controller.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT);
+
+ assertTrue(controller.isSendingSmartReply(TEST_NOTIFICATION_KEY));
+ }
+
+ @Test
+ public void testSendingSmartReply_afterRemove_shouldReturnFalse() {
+ SmartReplyController controller = new SmartReplyController();
+ controller.isSendingSmartReply(TEST_NOTIFICATION_KEY);
+ controller.stopSending(mEntry);
+
+ assertFalse(controller.isSendingSmartReply(TEST_NOTIFICATION_KEY));
+ }
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6f572df..4c2a940 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -64,6 +64,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.NeededUriGrants;
@@ -2012,6 +2013,25 @@
+ why + " of " + r + " in app " + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
+ why + " of " + r.shortName);
+
+ // For b/34123235: Services within the system server won't start until SystemServer
+ // does Looper.loop(), so we shouldn't try to start/bind to them too early in the boot
+ // process. However, since there's a little point of showing the ANR dialog in that case,
+ // let's suppress the timeout until PHASE_THIRD_PARTY_APPS_CAN_START.
+ //
+ // (Note there are multiple services start at PHASE_THIRD_PARTY_APPS_CAN_START too,
+ // which technically could also trigger this timeout if there's a system server
+ // that takes a long time to handle PHASE_THIRD_PARTY_APPS_CAN_START, but that shouldn't
+ // happen.)
+ boolean timeoutNeeded = true;
+ if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
+ && (r.app != null) && (r.app.pid == android.os.Process.myPid())) {
+
+ Slog.w(TAG, "Too early to start/bind service in system_server: Phase=" + mAm.mBootPhase
+ + " " + r.getComponentName());
+ timeoutNeeded = false;
+ }
+
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
@@ -2022,13 +2042,15 @@
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
- if (r.app.executingServices.size() == 1) {
+ if (timeoutNeeded && r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
- scheduleServiceTimeoutLocked(r.app);
+ if (timeoutNeeded) {
+ scheduleServiceTimeoutLocked(r.app);
+ }
}
r.executeFg |= fg;
r.executeNesting++;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70648c6..113f452 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1850,6 +1850,11 @@
*/
boolean mBooted = false;
+ /**
+ * Current boot phase.
+ */
+ int mBootPhase;
+
WindowManagerService mWindowManager;
final ActivityThread mSystemThread;
@@ -2881,6 +2886,7 @@
@Override
public void onBootPhase(int phase) {
+ mService.mBootPhase = phase;
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 5764382..ddf9552 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -132,6 +132,8 @@
if (showingChanged) {
dismissDockedStackIfNeeded();
setKeyguardGoingAway(false);
+ mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
+ isKeyguardOrAodShowing(DEFAULT_DISPLAY));
if (keyguardShowing) {
mDismissalRequested = false;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fe2fd532..42215c9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5082,7 +5082,7 @@
final int fl = PolicyControl.getWindowFlags(win, attrs);
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
- final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+ final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
final Rect pf = mTmpParentFrame;
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
index 3f26d86..48e72bc 100644
--- a/services/core/java/com/android/server/policy/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -65,7 +65,8 @@
public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
attrs = attrs != null ? attrs : win.getAttrs();
- int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+ int vis = win != null ? win.getSystemUiVisibility()
+ : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 39a3629..cd8d677 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -692,7 +692,7 @@
// Do not minimize when dock is already minimized while keyguard is showing and not
// occluded such as unlocking the screen
- if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
+ if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
return;
}
final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 16399008..cb64142 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -369,7 +369,10 @@
final WindowTracing mWindowTracing;
final private KeyguardDisableHandler mKeyguardDisableHandler;
+ // TODO: eventually unify all keyguard state in a common place instead of having it spread over
+ // AM's KeyguardController and the policy's KeyguardServiceDelegate.
boolean mKeyguardGoingAway;
+ boolean mKeyguardOrAodShowingOnDefaultDisplay;
// VR Vr2d Display Id.
int mVr2dDisplayId = INVALID_DISPLAY;
@@ -2909,6 +2912,12 @@
}
}
+ public void setKeyguardOrAodShowingOnDefaultDisplay(boolean showing) {
+ synchronized (mWindowMap) {
+ mKeyguardOrAodShowingOnDefaultDisplay = showing;
+ }
+ }
+
// -------------------------------------------------------------
// Misc IWindowSession methods
// -------------------------------------------------------------
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 91c449b..4e12daf 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -409,7 +409,7 @@
final Rect mContainingFrame = new Rect();
- private final Rect mParentFrame = new Rect();
+ final Rect mParentFrame = new Rect();
/** Whether the parent frame would have been different if there was no display cutout. */
private boolean mParentFrameWasClippedByDisplayCutout;
@@ -931,6 +931,17 @@
mContainingFrame.set(contentFrame);
}
}
+
+ final TaskStack stack = getStack();
+ if (inPinnedWindowingMode() && stack != null
+ && stack.lastAnimatingBoundsWasToFullscreen()) {
+ // PIP edge case: When going from pinned to fullscreen, we apply a
+ // tempInsetFrame for the full task - but we're still at the start of the animation.
+ // To prevent a jump if there's a letterbox, restrict to the parent frame.
+ mInsetFrame.intersectUnchecked(parentFrame);
+ mContainingFrame.intersectUnchecked(parentFrame);
+ }
+
mDisplayFrame.set(mContainingFrame);
layoutXDiff = !mInsetFrame.isEmpty() ? mInsetFrame.left - mContainingFrame.left : 0;
layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 4a6587b..c44a582 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -927,6 +927,13 @@
mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
allowStretching = true;
}
+
+ // Make sure that what we're animating to and from is actually the right size in case
+ // the window cannot take up the full screen.
+ mTmpStackBounds.intersectUnchecked(w.mParentFrame);
+ mTmpSourceBounds.intersectUnchecked(w.mParentFrame);
+ mTmpAnimatingBounds.intersectUnchecked(w.mParentFrame);
+
if (!mTmpSourceBounds.isEmpty()) {
// Get the final target stack bounds, if we are not animating, this is just the
// current stack bounds