Loading cmds/screencap/screencap.cpp +20 −19 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <binder/ProcessState.h> #include <binder/ProcessState.h> #include <ftl/concat.h> #include <ftl/optional.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceComposerClient.h> #include <gui/SyncScreenCaptureListener.h> #include <gui/SyncScreenCaptureListener.h> Loading @@ -45,14 +47,7 @@ using namespace android; #define COLORSPACE_SRGB 1 #define COLORSPACE_SRGB 1 #define COLORSPACE_DISPLAY_P3 2 #define COLORSPACE_DISPLAY_P3 2 static void usage(const char* pname, std::optional<PhysicalDisplayId> displayId) void usage(const char* pname, ftl::Optional<DisplayId> displayIdOpt) { { std::string defaultDisplayStr = ""; if (!displayId) { defaultDisplayStr = ""; } else { defaultDisplayStr = " (default: " + to_string(*displayId) + ")"; } fprintf(stderr, fprintf(stderr, "usage: %s [-hp] [-d display-id] [FILENAME]\n" "usage: %s [-hp] [-d display-id] [FILENAME]\n" " -h: this message\n" " -h: this message\n" Loading @@ -61,7 +56,13 @@ static void usage(const char* pname, std::optional<PhysicalDisplayId> displayId) " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n" " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME is not given, the results will be printed to stdout.\n", "If FILENAME is not given, the results will be printed to stdout.\n", pname, defaultDisplayStr.c_str()); pname, displayIdOpt .transform([](DisplayId id) { return std::string(ftl::Concat(" (default: ", id.value, ')').str()); }) .value_or(std::string()) .c_str()); } } static int32_t flinger2bitmapFormat(PixelFormat f) static int32_t flinger2bitmapFormat(PixelFormat f) Loading Loading @@ -132,7 +133,7 @@ int main(int argc, char** argv) fprintf(stderr, "Failed to get ID for any displays.\n"); fprintf(stderr, "Failed to get ID for any displays.\n"); return 1; return 1; } } std::optional<PhysicalDisplayId> displayId; std::optional<DisplayId> displayIdOpt; const char* pname = argv[0]; const char* pname = argv[0]; bool png = false; bool png = false; int c; int c; Loading @@ -142,8 +143,8 @@ int main(int argc, char** argv) png = true; png = true; break; break; case 'd': case 'd': displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg)); displayIdOpt = DisplayId::fromValue(atoll(optarg)); if (!displayId) { if (!displayIdOpt) { fprintf(stderr, "Invalid display ID: %s\n", optarg); fprintf(stderr, "Invalid display ID: %s\n", optarg); return 1; return 1; } } Loading @@ -151,15 +152,15 @@ int main(int argc, char** argv) case '?': case '?': case 'h': case 'h': if (ids.size() == 1) { if (ids.size() == 1) { displayId = ids.front(); displayIdOpt = ids.front(); } } usage(pname, displayId); usage(pname, displayIdOpt); return 1; return 1; } } } } if (!displayId) { // no diplsay id is specified if (!displayIdOpt) { displayId = ids.front(); displayIdOpt = ids.front(); if (ids.size() > 1) { if (ids.size() > 1) { fprintf(stderr, fprintf(stderr, "[Warning] Multiple displays were found, but no display id was specified! " "[Warning] Multiple displays were found, but no display id was specified! " Loading Loading @@ -191,7 +192,7 @@ int main(int argc, char** argv) } } if (fd == -1) { if (fd == -1) { usage(pname, displayId); usage(pname, displayIdOpt); return 1; return 1; } } Loading @@ -208,7 +209,7 @@ int main(int argc, char** argv) ProcessState::self()->startThreadPool(); ProcessState::self()->startThreadPool(); sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); status_t result = ScreenshotClient::captureDisplay(*displayId, captureListener); status_t result = ScreenshotClient::captureDisplay(*displayIdOpt, captureListener); if (result != NO_ERROR) { if (result != NO_ERROR) { close(fd); close(fd); return 1; return 1; Loading core/java/android/window/WindowOnBackInvokedDispatcher.java +5 −1 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,8 @@ import android.util.Log; import android.view.IWindow; import android.view.IWindow; import android.view.IWindowSession; import android.view.IWindowSession; import androidx.annotation.VisibleForTesting; import java.io.PrintWriter; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; Loading Loading @@ -66,7 +68,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { /** Convenience hashmap to quickly decide if a callback has been added. */ /** Convenience hashmap to quickly decide if a callback has been added. */ private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>(); private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>(); /** Holds all callbacks by priorities. */ /** Holds all callbacks by priorities. */ private final TreeMap<Integer, ArrayList<OnBackInvokedCallback>> @VisibleForTesting public final TreeMap<Integer, ArrayList<OnBackInvokedCallback>> mOnBackInvokedCallbacks = new TreeMap<>(); mOnBackInvokedCallbacks = new TreeMap<>(); private Checker mChecker; private Checker mChecker; Loading core/res/res/layout/language_picker_section_header.xml +2 −1 Original line number Original line Diff line number Diff line Loading @@ -25,4 +25,5 @@ android:textColor="?android:attr/colorAccent" android:textColor="?android:attr/colorAccent" android:textStyle="bold" android:textStyle="bold" android:id="@+id/language_picker_header" android:id="@+id/language_picker_header" tools:text="@string/language_picker_section_all"/> tools:text="@string/language_picker_section_all" android:scrollbars="none"/> core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java +203 −57 Original line number Original line Diff line number Diff line Loading @@ -16,12 +16,15 @@ package android.window; package android.window; import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT; import static android.window.OnBackInvokedDispatcher.PRIORITY_OVERLAY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions; Loading @@ -45,6 +48,9 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; /** /** * Tests for {@link WindowOnBackInvokedDispatcherTest} * Tests for {@link WindowOnBackInvokedDispatcherTest} * * Loading @@ -69,6 +75,8 @@ public class WindowOnBackInvokedDispatcherTest { @Mock @Mock private ApplicationInfo mApplicationInfo; private ApplicationInfo mApplicationInfo; private int mCallbackInfoCalls = 0; private final BackMotionEvent mBackEvent = new BackMotionEvent( private final BackMotionEvent mBackEvent = new BackMotionEvent( /* touchX = */ 0, /* touchX = */ 0, /* touchY = */ 0, /* touchY = */ 0, Loading @@ -93,105 +101,243 @@ public class WindowOnBackInvokedDispatcherTest { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } } private List<OnBackInvokedCallbackInfo> captureCallbackInfo() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = ArgumentCaptor .forClass(OnBackInvokedCallbackInfo.class); // atLeast(0) -> get all setOnBackInvokedCallbackInfo() invocations verify(mWindowSession, atLeast(0)) .setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture()); verifyNoMoreInteractions(mWindowSession); return captor.getAllValues(); } private OnBackInvokedCallbackInfo assertSetCallbackInfo() throws RemoteException { List<OnBackInvokedCallbackInfo> callbackInfos = captureCallbackInfo(); int actual = callbackInfos.size(); assertEquals("setOnBackInvokedCallbackInfo", ++mCallbackInfoCalls, actual); return callbackInfos.get(mCallbackInfoCalls - 1); } private void assertNoSetCallbackInfo() throws RemoteException { List<OnBackInvokedCallbackInfo> callbackInfos = captureCallbackInfo(); int actual = callbackInfos.size(); assertEquals("No setOnBackInvokedCallbackInfo", mCallbackInfoCalls, actual); } private void assertCallbacksSize(int expectedDefault, int expectedOverlay) { ArrayList<OnBackInvokedCallback> callbacksDefault = mDispatcher .mOnBackInvokedCallbacks.get(PRIORITY_DEFAULT); int actualSizeDefault = callbacksDefault != null ? callbacksDefault.size() : 0; assertEquals("mOnBackInvokedCallbacks DEFAULT size", expectedDefault, actualSizeDefault); ArrayList<OnBackInvokedCallback> callbacksOverlay = mDispatcher .mOnBackInvokedCallbacks.get(PRIORITY_OVERLAY); int actualSizeOverlay = callbacksOverlay != null ? callbacksOverlay.size() : 0; assertEquals("mOnBackInvokedCallbacks OVERLAY size", expectedOverlay, actualSizeOverlay); } private void assertTopCallback(OnBackInvokedCallback expectedCallback) { assertEquals("topCallback", expectedCallback, mDispatcher.getTopCallback()); } @Test public void registerCallback_samePriority_sameCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); // The callback is removed and added again mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); } @Test public void registerCallback_samePriority_differentCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); // The new callback becomes the TopCallback mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertCallbacksSize(/* default */ 2, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback2); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback2); } @Test public void registerCallback_differentPriority_sameCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); assertCallbacksSize(/* default */ 0, /* overlay */ 1); assertSetCallbackInfo(); assertTopCallback(mCallback1); // The callback is moved to the new priority list mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); } @Test public void registerCallback_differentPriority_differentCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); assertSetCallbackInfo(); assertCallbacksSize(/* default */ 0, /* overlay */ 1); assertTopCallback(mCallback1); // The callback with higher priority is still the TopCallback mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertNoSetCallbackInfo(); assertCallbacksSize(/* default */ 1, /* overlay */ 1); assertTopCallback(mCallback1); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback2); } @Test public void registerCallback_sameInstanceAddedTwice() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); assertCallbacksSize(/* default */ 0, /* overlay */ 1); assertSetCallbackInfo(); assertTopCallback(mCallback1); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertCallbacksSize(/* default */ 1, /* overlay */ 1); assertNoSetCallbackInfo(); assertTopCallback(mCallback1); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 2, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback2); assertCallbacksSize(/* default */ 1, /* overlay */ 1); assertSetCallbackInfo(); assertTopCallback(mCallback2); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback2); } @Test @Test public void propagatesTopCallback_samePriority() throws RemoteException { public void propagatesTopCallback_samePriority() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); OnBackInvokedCallbackInfo callbackInfo1 = assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); OnBackInvokedCallbackInfo callbackInfo2 = assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); callbackInfo1.getCallback().onBackStarted(mBackEvent); verify(mWindowSession, times(2)).setOnBackInvokedCallbackInfo( Mockito.eq(mWindow), captor.capture()); captor.getAllValues().get(0).getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback1).onBackStarted(any(BackEvent.class)); verify(mCallback1).onBackStarted(any(BackEvent.class)); verifyZeroInteractions(mCallback2); verifyZeroInteractions(mCallback2); captor.getAllValues().get(1).getCallback().onBackStarted(mBackEvent); callbackInfo2.getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback2).onBackStarted(any(BackEvent.class)); verify(mCallback2).onBackStarted(any(BackEvent.class)); // Calls sequence: BackProgressAnimator.onBackStarted() -> BackProgressAnimator.reset() -> // Spring.animateToFinalPosition(0). This causes a progress event to be fired. verify(mCallback1, atMost(1)).onBackProgressed(any(BackEvent.class)); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback1); } } @Test @Test public void propagatesTopCallback_differentPriority() throws RemoteException { public void propagatesTopCallback_differentPriority() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo(); OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback1); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); verify(mWindowSession).setOnBackInvokedCallbackInfo( Mockito.eq(mWindow), captor.capture()); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mWindowSession); assertEquals(captor.getValue().getPriority(), OnBackInvokedDispatcher.PRIORITY_OVERLAY); assertEquals(callbackInfo.getPriority(), PRIORITY_OVERLAY); captor.getValue().getCallback().onBackStarted(mBackEvent); callbackInfo.getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback1).onBackStarted(any(BackEvent.class)); verify(mCallback1).onBackStarted(any(BackEvent.class)); } } @Test @Test public void propagatesTopCallback_withRemoval() throws RemoteException { public void propagatesTopCallback_withRemoval() throws RemoteException { mDispatcher.registerOnBackInvokedCallback( mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertSetCallbackInfo(); reset(mWindowSession); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); verifyZeroInteractions(mWindowSession); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); mDispatcher.unregisterOnBackInvokedCallback(mCallback2); mDispatcher.unregisterOnBackInvokedCallback(mCallback2); waitForIdle(); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull()); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull()); } } @Test @Test public void propagatesTopCallback_sameInstanceAddedTwice() throws RemoteException { public void propagatesTopCallback_sameInstanceAddedTwice() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_OVERLAY, assertNoSetCallbackInfo(); mCallback1 mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); ); assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback2); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); OnBackInvokedCallbackInfo lastCallbackInfo = assertSetCallbackInfo(); reset(mWindowSession); lastCallbackInfo.getCallback().onBackStarted(mBackEvent); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback2); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture()); captor.getValue().getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback2).onBackStarted(any(BackEvent.class)); verify(mCallback2).onBackStarted(any(BackEvent.class)); } } @Test @Test public void onUnregisterWhileBackInProgress_callOnBackCancelled() throws RemoteException { public void onUnregisterWhileBackInProgress_callOnBackCancelled() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo(); OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); callbackInfo.getCallback().onBackStarted(mBackEvent); verify(mWindowSession).setOnBackInvokedCallbackInfo( Mockito.eq(mWindow), captor.capture()); IOnBackInvokedCallback iOnBackInvokedCallback = captor.getValue().getCallback(); iOnBackInvokedCallback.onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback1).onBackStarted(any(BackEvent.class)); verify(mCallback1).onBackStarted(any(BackEvent.class)); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); waitForIdle(); verify(mCallback1).onBackCancelled(); verify(mCallback1).onBackCancelled(); verifyNoMoreInteractions(mCallback1); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull()); } } } } libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -166,7 +166,7 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler "unocclude", "unocclude", transition, info, startTransaction, finishTransaction, finishCallback); transition, info, startTransaction, finishTransaction, finishCallback); } else { } else { Log.wtf(TAG, "Failed to play: " + info); Log.w(TAG, "Failed to play: " + info); return false; return false; } } } } Loading Loading
cmds/screencap/screencap.cpp +20 −19 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <binder/ProcessState.h> #include <binder/ProcessState.h> #include <ftl/concat.h> #include <ftl/optional.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceComposerClient.h> #include <gui/SyncScreenCaptureListener.h> #include <gui/SyncScreenCaptureListener.h> Loading @@ -45,14 +47,7 @@ using namespace android; #define COLORSPACE_SRGB 1 #define COLORSPACE_SRGB 1 #define COLORSPACE_DISPLAY_P3 2 #define COLORSPACE_DISPLAY_P3 2 static void usage(const char* pname, std::optional<PhysicalDisplayId> displayId) void usage(const char* pname, ftl::Optional<DisplayId> displayIdOpt) { { std::string defaultDisplayStr = ""; if (!displayId) { defaultDisplayStr = ""; } else { defaultDisplayStr = " (default: " + to_string(*displayId) + ")"; } fprintf(stderr, fprintf(stderr, "usage: %s [-hp] [-d display-id] [FILENAME]\n" "usage: %s [-hp] [-d display-id] [FILENAME]\n" " -h: this message\n" " -h: this message\n" Loading @@ -61,7 +56,13 @@ static void usage(const char* pname, std::optional<PhysicalDisplayId> displayId) " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n" " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME is not given, the results will be printed to stdout.\n", "If FILENAME is not given, the results will be printed to stdout.\n", pname, defaultDisplayStr.c_str()); pname, displayIdOpt .transform([](DisplayId id) { return std::string(ftl::Concat(" (default: ", id.value, ')').str()); }) .value_or(std::string()) .c_str()); } } static int32_t flinger2bitmapFormat(PixelFormat f) static int32_t flinger2bitmapFormat(PixelFormat f) Loading Loading @@ -132,7 +133,7 @@ int main(int argc, char** argv) fprintf(stderr, "Failed to get ID for any displays.\n"); fprintf(stderr, "Failed to get ID for any displays.\n"); return 1; return 1; } } std::optional<PhysicalDisplayId> displayId; std::optional<DisplayId> displayIdOpt; const char* pname = argv[0]; const char* pname = argv[0]; bool png = false; bool png = false; int c; int c; Loading @@ -142,8 +143,8 @@ int main(int argc, char** argv) png = true; png = true; break; break; case 'd': case 'd': displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg)); displayIdOpt = DisplayId::fromValue(atoll(optarg)); if (!displayId) { if (!displayIdOpt) { fprintf(stderr, "Invalid display ID: %s\n", optarg); fprintf(stderr, "Invalid display ID: %s\n", optarg); return 1; return 1; } } Loading @@ -151,15 +152,15 @@ int main(int argc, char** argv) case '?': case '?': case 'h': case 'h': if (ids.size() == 1) { if (ids.size() == 1) { displayId = ids.front(); displayIdOpt = ids.front(); } } usage(pname, displayId); usage(pname, displayIdOpt); return 1; return 1; } } } } if (!displayId) { // no diplsay id is specified if (!displayIdOpt) { displayId = ids.front(); displayIdOpt = ids.front(); if (ids.size() > 1) { if (ids.size() > 1) { fprintf(stderr, fprintf(stderr, "[Warning] Multiple displays were found, but no display id was specified! " "[Warning] Multiple displays were found, but no display id was specified! " Loading Loading @@ -191,7 +192,7 @@ int main(int argc, char** argv) } } if (fd == -1) { if (fd == -1) { usage(pname, displayId); usage(pname, displayIdOpt); return 1; return 1; } } Loading @@ -208,7 +209,7 @@ int main(int argc, char** argv) ProcessState::self()->startThreadPool(); ProcessState::self()->startThreadPool(); sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); status_t result = ScreenshotClient::captureDisplay(*displayId, captureListener); status_t result = ScreenshotClient::captureDisplay(*displayIdOpt, captureListener); if (result != NO_ERROR) { if (result != NO_ERROR) { close(fd); close(fd); return 1; return 1; Loading
core/java/android/window/WindowOnBackInvokedDispatcher.java +5 −1 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,8 @@ import android.util.Log; import android.view.IWindow; import android.view.IWindow; import android.view.IWindowSession; import android.view.IWindowSession; import androidx.annotation.VisibleForTesting; import java.io.PrintWriter; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; Loading Loading @@ -66,7 +68,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { /** Convenience hashmap to quickly decide if a callback has been added. */ /** Convenience hashmap to quickly decide if a callback has been added. */ private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>(); private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>(); /** Holds all callbacks by priorities. */ /** Holds all callbacks by priorities. */ private final TreeMap<Integer, ArrayList<OnBackInvokedCallback>> @VisibleForTesting public final TreeMap<Integer, ArrayList<OnBackInvokedCallback>> mOnBackInvokedCallbacks = new TreeMap<>(); mOnBackInvokedCallbacks = new TreeMap<>(); private Checker mChecker; private Checker mChecker; Loading
core/res/res/layout/language_picker_section_header.xml +2 −1 Original line number Original line Diff line number Diff line Loading @@ -25,4 +25,5 @@ android:textColor="?android:attr/colorAccent" android:textColor="?android:attr/colorAccent" android:textStyle="bold" android:textStyle="bold" android:id="@+id/language_picker_header" android:id="@+id/language_picker_header" tools:text="@string/language_picker_section_all"/> tools:text="@string/language_picker_section_all" android:scrollbars="none"/>
core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java +203 −57 Original line number Original line Diff line number Diff line Loading @@ -16,12 +16,15 @@ package android.window; package android.window; import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT; import static android.window.OnBackInvokedDispatcher.PRIORITY_OVERLAY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions; Loading @@ -45,6 +48,9 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; /** /** * Tests for {@link WindowOnBackInvokedDispatcherTest} * Tests for {@link WindowOnBackInvokedDispatcherTest} * * Loading @@ -69,6 +75,8 @@ public class WindowOnBackInvokedDispatcherTest { @Mock @Mock private ApplicationInfo mApplicationInfo; private ApplicationInfo mApplicationInfo; private int mCallbackInfoCalls = 0; private final BackMotionEvent mBackEvent = new BackMotionEvent( private final BackMotionEvent mBackEvent = new BackMotionEvent( /* touchX = */ 0, /* touchX = */ 0, /* touchY = */ 0, /* touchY = */ 0, Loading @@ -93,105 +101,243 @@ public class WindowOnBackInvokedDispatcherTest { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } } private List<OnBackInvokedCallbackInfo> captureCallbackInfo() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = ArgumentCaptor .forClass(OnBackInvokedCallbackInfo.class); // atLeast(0) -> get all setOnBackInvokedCallbackInfo() invocations verify(mWindowSession, atLeast(0)) .setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture()); verifyNoMoreInteractions(mWindowSession); return captor.getAllValues(); } private OnBackInvokedCallbackInfo assertSetCallbackInfo() throws RemoteException { List<OnBackInvokedCallbackInfo> callbackInfos = captureCallbackInfo(); int actual = callbackInfos.size(); assertEquals("setOnBackInvokedCallbackInfo", ++mCallbackInfoCalls, actual); return callbackInfos.get(mCallbackInfoCalls - 1); } private void assertNoSetCallbackInfo() throws RemoteException { List<OnBackInvokedCallbackInfo> callbackInfos = captureCallbackInfo(); int actual = callbackInfos.size(); assertEquals("No setOnBackInvokedCallbackInfo", mCallbackInfoCalls, actual); } private void assertCallbacksSize(int expectedDefault, int expectedOverlay) { ArrayList<OnBackInvokedCallback> callbacksDefault = mDispatcher .mOnBackInvokedCallbacks.get(PRIORITY_DEFAULT); int actualSizeDefault = callbacksDefault != null ? callbacksDefault.size() : 0; assertEquals("mOnBackInvokedCallbacks DEFAULT size", expectedDefault, actualSizeDefault); ArrayList<OnBackInvokedCallback> callbacksOverlay = mDispatcher .mOnBackInvokedCallbacks.get(PRIORITY_OVERLAY); int actualSizeOverlay = callbacksOverlay != null ? callbacksOverlay.size() : 0; assertEquals("mOnBackInvokedCallbacks OVERLAY size", expectedOverlay, actualSizeOverlay); } private void assertTopCallback(OnBackInvokedCallback expectedCallback) { assertEquals("topCallback", expectedCallback, mDispatcher.getTopCallback()); } @Test public void registerCallback_samePriority_sameCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); // The callback is removed and added again mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); } @Test public void registerCallback_samePriority_differentCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); // The new callback becomes the TopCallback mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertCallbacksSize(/* default */ 2, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback2); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback2); } @Test public void registerCallback_differentPriority_sameCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); assertCallbacksSize(/* default */ 0, /* overlay */ 1); assertSetCallbackInfo(); assertTopCallback(mCallback1); // The callback is moved to the new priority list mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 1, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); } @Test public void registerCallback_differentPriority_differentCallback() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); assertSetCallbackInfo(); assertCallbacksSize(/* default */ 0, /* overlay */ 1); assertTopCallback(mCallback1); // The callback with higher priority is still the TopCallback mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertNoSetCallbackInfo(); assertCallbacksSize(/* default */ 1, /* overlay */ 1); assertTopCallback(mCallback1); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback2); } @Test public void registerCallback_sameInstanceAddedTwice() throws RemoteException { mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); assertCallbacksSize(/* default */ 0, /* overlay */ 1); assertSetCallbackInfo(); assertTopCallback(mCallback1); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertCallbacksSize(/* default */ 1, /* overlay */ 1); assertNoSetCallbackInfo(); assertTopCallback(mCallback1); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); assertCallbacksSize(/* default */ 2, /* overlay */ 0); assertSetCallbackInfo(); assertTopCallback(mCallback1); mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback2); assertCallbacksSize(/* default */ 1, /* overlay */ 1); assertSetCallbackInfo(); assertTopCallback(mCallback2); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback2); } @Test @Test public void propagatesTopCallback_samePriority() throws RemoteException { public void propagatesTopCallback_samePriority() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); OnBackInvokedCallbackInfo callbackInfo1 = assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); OnBackInvokedCallbackInfo callbackInfo2 = assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); callbackInfo1.getCallback().onBackStarted(mBackEvent); verify(mWindowSession, times(2)).setOnBackInvokedCallbackInfo( Mockito.eq(mWindow), captor.capture()); captor.getAllValues().get(0).getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback1).onBackStarted(any(BackEvent.class)); verify(mCallback1).onBackStarted(any(BackEvent.class)); verifyZeroInteractions(mCallback2); verifyZeroInteractions(mCallback2); captor.getAllValues().get(1).getCallback().onBackStarted(mBackEvent); callbackInfo2.getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback2).onBackStarted(any(BackEvent.class)); verify(mCallback2).onBackStarted(any(BackEvent.class)); // Calls sequence: BackProgressAnimator.onBackStarted() -> BackProgressAnimator.reset() -> // Spring.animateToFinalPosition(0). This causes a progress event to be fired. verify(mCallback1, atMost(1)).onBackProgressed(any(BackEvent.class)); verifyNoMoreInteractions(mCallback1); verifyNoMoreInteractions(mCallback1); } } @Test @Test public void propagatesTopCallback_differentPriority() throws RemoteException { public void propagatesTopCallback_differentPriority() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo(); OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback1); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); verify(mWindowSession).setOnBackInvokedCallbackInfo( Mockito.eq(mWindow), captor.capture()); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mWindowSession); assertEquals(captor.getValue().getPriority(), OnBackInvokedDispatcher.PRIORITY_OVERLAY); assertEquals(callbackInfo.getPriority(), PRIORITY_OVERLAY); captor.getValue().getCallback().onBackStarted(mBackEvent); callbackInfo.getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback1).onBackStarted(any(BackEvent.class)); verify(mCallback1).onBackStarted(any(BackEvent.class)); } } @Test @Test public void propagatesTopCallback_withRemoval() throws RemoteException { public void propagatesTopCallback_withRemoval() throws RemoteException { mDispatcher.registerOnBackInvokedCallback( mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); assertSetCallbackInfo(); reset(mWindowSession); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); verifyZeroInteractions(mWindowSession); waitForIdle(); verifyNoMoreInteractions(mWindowSession); verifyNoMoreInteractions(mCallback1); mDispatcher.unregisterOnBackInvokedCallback(mCallback2); mDispatcher.unregisterOnBackInvokedCallback(mCallback2); waitForIdle(); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull()); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull()); } } @Test @Test public void propagatesTopCallback_sameInstanceAddedTwice() throws RemoteException { public void propagatesTopCallback_sameInstanceAddedTwice() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_OVERLAY, assertNoSetCallbackInfo(); mCallback1 mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); ); assertSetCallbackInfo(); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2); mDispatcher.registerOnBackInvokedCallback(PRIORITY_OVERLAY, mCallback2); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); OnBackInvokedCallbackInfo lastCallbackInfo = assertSetCallbackInfo(); reset(mWindowSession); lastCallbackInfo.getCallback().onBackStarted(mBackEvent); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback2); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture()); captor.getValue().getCallback().onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback2).onBackStarted(any(BackEvent.class)); verify(mCallback2).onBackStarted(any(BackEvent.class)); } } @Test @Test public void onUnregisterWhileBackInProgress_callOnBackCancelled() throws RemoteException { public void onUnregisterWhileBackInProgress_callOnBackCancelled() throws RemoteException { ArgumentCaptor<OnBackInvokedCallbackInfo> captor = mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1); ArgumentCaptor.forClass(OnBackInvokedCallbackInfo.class); mDispatcher.registerOnBackInvokedCallback( OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo(); OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1); callbackInfo.getCallback().onBackStarted(mBackEvent); verify(mWindowSession).setOnBackInvokedCallbackInfo( Mockito.eq(mWindow), captor.capture()); IOnBackInvokedCallback iOnBackInvokedCallback = captor.getValue().getCallback(); iOnBackInvokedCallback.onBackStarted(mBackEvent); waitForIdle(); waitForIdle(); verify(mCallback1).onBackStarted(any(BackEvent.class)); verify(mCallback1).onBackStarted(any(BackEvent.class)); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); mDispatcher.unregisterOnBackInvokedCallback(mCallback1); waitForIdle(); verify(mCallback1).onBackCancelled(); verify(mCallback1).onBackCancelled(); verifyNoMoreInteractions(mCallback1); verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), isNull()); } } } }
libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -166,7 +166,7 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler "unocclude", "unocclude", transition, info, startTransaction, finishTransaction, finishCallback); transition, info, startTransaction, finishTransaction, finishCallback); } else { } else { Log.wtf(TAG, "Failed to play: " + info); Log.w(TAG, "Failed to play: " + info); return false; return false; } } } } Loading