Merge "Add Flaky annotation to 4 flaky tests in VibratorManagerServiceTest" into udc-qpr-dev
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b6c39c6..16e94f8 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1015,6 +1015,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
},
+ "-1152771606": {
+ "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"-1145384901": {
"message": "shouldWaitAnimatingExit: isTransition: %s",
"level": "DEBUG",
@@ -2323,6 +2329,12 @@
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1877956": {
+ "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"3593205": {
"message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
"level": "VERBOSE",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java
index 51eb9f7..c24e9dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManager.java
@@ -36,7 +36,7 @@
@SysUISingleton
public class NotifInflationErrorManager {
- Set<NotificationEntry> mErroredNotifs = new ArraySet<>();
+ Set<String> mErroredNotifs = new ArraySet<>();
List<NotifInflationErrorListener> mListeners = new ArrayList<>();
@Inject
@@ -48,7 +48,7 @@
* @param e the exception encountered while inflating
*/
public void setInflationError(NotificationEntry entry, Exception e) {
- mErroredNotifs.add(entry);
+ mErroredNotifs.add(entry.getKey());
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onNotifInflationError(entry, e);
}
@@ -58,8 +58,8 @@
* Notification inflated successfully and is no longer errored out.
*/
public void clearInflationError(NotificationEntry entry) {
- if (mErroredNotifs.contains(entry)) {
- mErroredNotifs.remove(entry);
+ if (mErroredNotifs.contains(entry.getKey())) {
+ mErroredNotifs.remove(entry.getKey());
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onNotifInflationErrorCleared(entry);
}
@@ -70,7 +70,7 @@
* Whether or not the notification encountered an exception while inflating.
*/
public boolean hasInflationError(@NonNull NotificationEntry entry) {
- return mErroredNotifs.contains(entry);
+ return mErroredNotifs.contains(entry.getKey());
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
new file mode 100644
index 0000000..e38adeb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 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 com.android.systemui.statusbar.notification.row
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager.NotifInflationErrorListener
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class NotifInflationErrorManagerTest : SysuiTestCase() {
+ private lateinit var manager: NotifInflationErrorManager
+
+ private val listener1 = mock(NotifInflationErrorListener::class.java)
+ private val listener2 = mock(NotifInflationErrorListener::class.java)
+
+ private val foo: NotificationEntry = NotificationEntryBuilder().setPkg("foo").build()
+ private val bar: NotificationEntry = NotificationEntryBuilder().setPkg("bar").build()
+ private val baz: NotificationEntry = NotificationEntryBuilder().setPkg("baz").build()
+
+ private val fooException = Exception("foo")
+ private val barException = Exception("bar")
+
+ @Before
+ fun setUp() {
+ // Reset manager instance before each test.
+ manager = NotifInflationErrorManager()
+ }
+
+ @Test
+ fun testTracksInflationErrors() {
+ manager.setInflationError(foo, fooException)
+ manager.setInflationError(bar, barException)
+
+ assertThat(manager.hasInflationError(foo)).isTrue()
+ assertThat(manager.hasInflationError(bar)).isTrue()
+ assertThat(manager.hasInflationError(baz)).isFalse()
+
+ manager.clearInflationError(bar)
+
+ assertThat(manager.hasInflationError(bar)).isFalse()
+ }
+
+ @Test
+ fun testNotifiesListeners() {
+ manager.addInflationErrorListener(listener1)
+ manager.setInflationError(foo, fooException)
+
+ verify(listener1).onNotifInflationError(foo, fooException)
+
+ manager.addInflationErrorListener(listener2)
+ manager.setInflationError(bar, barException)
+
+ verify(listener1).onNotifInflationError(bar, barException)
+ verify(listener2).onNotifInflationError(bar, barException)
+
+ manager.clearInflationError(foo)
+
+ verify(listener1).onNotifInflationErrorCleared(foo)
+ verify(listener2).onNotifInflationErrorCleared(foo)
+ }
+
+ @Test
+ fun testClearUnknownEntry() {
+ manager.addInflationErrorListener(listener1)
+ manager.clearInflationError(foo)
+
+ verify(listener1, never()).onNotifInflationErrorCleared(any())
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 309a9c0..5b25e89 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -321,9 +321,6 @@
if (DEBUG) {
Slog.d(TAG, "publish system wallpaper changed!");
}
- if (localSync != null) {
- localSync.complete();
- }
notifyWallpaperChanged(wallpaper);
}
};
@@ -331,7 +328,7 @@
// If this was the system wallpaper, rebind...
bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper,
callback);
- notifyColorsWhich |= FLAG_SYSTEM;
+ notifyColorsWhich |= wallpaper.mWhich;
}
if (lockWallpaperChanged) {
@@ -345,9 +342,6 @@
if (DEBUG) {
Slog.d(TAG, "publish lock wallpaper changed!");
}
- if (localSync != null) {
- localSync.complete();
- }
notifyWallpaperChanged(wallpaper);
}
};
@@ -372,9 +366,8 @@
}
saveSettingsLocked(wallpaper.userId);
- // Notify the client immediately if only lockscreen wallpaper changed.
- if (lockWallpaperChanged && !sysWallpaperChanged) {
- notifyWallpaperChanged(wallpaper);
+ if ((sysWallpaperChanged || lockWallpaperChanged) && localSync != null) {
+ localSync.complete();
}
}
@@ -1383,7 +1376,6 @@
lockWp.connection.mWallpaper = lockWp;
mOriginalSystem.mWhich = FLAG_LOCK;
updateEngineFlags(mOriginalSystem);
- notifyWallpaperColorsChanged(lockWp, FLAG_LOCK);
} else {
// Failed rename, use current system wp for both
if (DEBUG) {
@@ -1403,7 +1395,6 @@
updateEngineFlags(mOriginalSystem);
mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem);
mLastLockWallpaper = mOriginalSystem;
- notifyWallpaperColorsChanged(mOriginalSystem, FLAG_LOCK);
}
} else if (mNewWallpaper.mWhich == FLAG_LOCK) {
// New wp is lock only, so old system+lock is now system only
@@ -1417,10 +1408,7 @@
}
}
}
-
- synchronized (mLock) {
- saveSettingsLocked(mNewWallpaper.userId);
- }
+ saveSettingsLocked(mNewWallpaper.userId);
if (DEBUG) {
Slog.v(TAG, "--- wallpaper changed --");
@@ -3300,7 +3288,6 @@
if (DEBUG) {
Slog.d(TAG, "publish system wallpaper changed!");
}
- liveSync.complete();
}
};
@@ -3356,6 +3343,7 @@
}
mLockWallpaperMap.remove(newWallpaper.userId);
}
+ if (liveSync != null) liveSync.complete();
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -3474,6 +3462,11 @@
}
// Has the component changed?
if (!force && changingToSame(componentName, wallpaper)) {
+ try {
+ if (reply != null) reply.sendResult(null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send callback", e);
+ }
return true;
}
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index f0e4149..7cd07d6 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -151,6 +151,20 @@
return;
}
+ // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are
+ // inaccurate.
+ if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+ final Task capturedTask = mRecordedWindowContainer.asTask();
+ if (capturedTask.inPinnedWindowingMode()) {
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Display %d was already recording, but "
+ + "pause capture since the task is in PIP",
+ mDisplayContent.getDisplayId());
+ pauseRecording();
+ return;
+ }
+ }
+
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
"Content Recording: Display %d was already recording, so apply "
+ "transformations if necessary",
@@ -292,6 +306,17 @@
return;
}
+ // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are inaccurate.
+ if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+ if (mRecordedWindowContainer.asTask().inPinnedWindowingMode()) {
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Display %d should start recording, but "
+ + "don't yet since the task is in PIP",
+ mDisplayContent.getDisplayId());
+ return;
+ }
+ }
+
final Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize == null) {
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
@@ -305,9 +330,6 @@
+ "state %d",
mDisplayContent.getDisplayId(), mDisplayContent.getDisplayInfo().state);
- // TODO(b/274790702): Do not start recording if waiting for consent - for now,
- // go ahead.
-
// Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
mRecordedSurface = SurfaceControl.mirrorSurface(
mRecordedWindowContainer.getSurfaceControl());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index aa2b935..b8f6cb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -360,6 +363,39 @@
}
@Test
+ public void testTaskWindowingModeChanged_pip_stopsRecording() {
+ // WHEN a recording is ongoing.
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ // WHEN a configuration change arrives, and the task is now pinned.
+ mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+ Configuration configuration = mTask.getConfiguration();
+ mTask.onConfigurationChanged(configuration);
+
+ // THEN recording is paused.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testTaskWindowingModeChanged_fullscreen_startsRecording() {
+ // WHEN a recording is ongoing.
+ mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+
+ // WHEN the task is now fullscreen.
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mContentRecorder.updateRecording();
+
+ // THEN recording is started.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
public void testStartRecording_notifiesCallback_taskSession() {
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
@@ -384,6 +420,45 @@
}
@Test
+ public void testStartRecording_taskInPIP_recordingNotStarted() {
+ // GIVEN a task is in PIP.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mTask.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ // WHEN a recording tries to start.
+ mContentRecorder.updateRecording();
+
+ // THEN recording does not start.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testStartRecording_taskInSplit_recordingStarted() {
+ // GIVEN a task is in PIP.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+
+ // WHEN a recording tries to start.
+ mContentRecorder.updateRecording();
+
+ // THEN recording does not start.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
+ public void testStartRecording_taskInFullscreen_recordingStarted() {
+ // GIVEN a task is in PIP.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ // WHEN a recording tries to start.
+ mContentRecorder.updateRecording();
+
+ // THEN recording does not start.
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+ }
+
+ @Test
public void testOnVisibleRequestedChanged_notifiesCallback() {
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);