Merge "Add new vibrator frequency profile for PWLE v2" into main
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index 3534624..f80ccf7 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -7,6 +7,18 @@
default_applicable_licenses: ["frameworks_base_license"],
}
+aconfig_declarations {
+ name: "bootanimation_flags",
+ package: "com.android.graphics.bootanimation.flags",
+ container: "system",
+ srcs: ["bootanimation_flags.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "libbootanimationflags",
+ aconfig_declarations: "bootanimation_flags",
+}
+
cc_defaults {
name: "bootanimation_defaults",
@@ -28,6 +40,10 @@
"liblog",
"libutils",
],
+
+ static_libs: [
+ "libbootanimationflags",
+ ],
}
// bootanimation executable
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 87c9fa4..14e2387 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_NDEBUG 0
+
#define LOG_TAG "BootAnimation"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -61,6 +62,8 @@
#include "BootAnimation.h"
+#include <com_android_graphics_bootanimation_flags.h>
+
#define ANIM_PATH_MAX 255
#define STR(x) #x
#define STRTO(x) STR(x)
@@ -448,19 +451,21 @@
auto token = SurfaceComposerClient::getPhysicalDisplayToken(
event.header.displayId);
- if (token != mBootAnimation->mDisplayToken) {
+ auto firstDisplay = mBootAnimation->mDisplays.front();
+ if (token != firstDisplay.displayToken) {
// ignore hotplug of a secondary display
continue;
}
DisplayMode displayMode;
const status_t error = SurfaceComposerClient::getActiveDisplayMode(
- mBootAnimation->mDisplayToken, &displayMode);
+ firstDisplay.displayToken, &displayMode);
if (error != NO_ERROR) {
SLOGE("Can't get active display mode.");
}
mBootAnimation->resizeSurface(displayMode.resolution.getWidth(),
- displayMode.resolution.getHeight());
+ displayMode.resolution.getHeight(),
+ firstDisplay);
}
}
} while (numEvents > 0);
@@ -506,91 +511,106 @@
status_t BootAnimation::readyToRun() {
ATRACE_CALL();
mAssets.addDefaultAssets();
+ return initDisplaysAndSurfaces();
+}
- const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
- if (ids.empty()) {
- SLOGE("Failed to get ID for any displays\n");
+status_t BootAnimation::initDisplaysAndSurfaces() {
+ std::vector<PhysicalDisplayId> displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (displayIds.empty()) {
+ SLOGE("Failed to get ID for any displays");
return NAME_NOT_FOUND;
}
- mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
- if (mDisplayToken == nullptr) {
- return NAME_NOT_FOUND;
+ // If Multi-Display isn't explicitly enabled, ignore all displays after the first one
+ if (!com::android::graphics::bootanimation::flags::multidisplay()) {
+ displayIds.erase(displayIds.begin() + 1, displayIds.end());
}
- DisplayMode displayMode;
- const status_t error =
- SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
- if (error != NO_ERROR) {
- return error;
+ for (const auto id : displayIds) {
+ if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
+ mDisplays.push_back({.displayToken = token});
+ } else {
+ SLOGE("Failed to get display token for a display");
+ SLOGE("Failed to get display token for display %" PRIu64, id.value);
+ return NAME_NOT_FOUND;
+ }
}
+ // Initialize EGL
+ mEgl = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mEgl, nullptr, nullptr);
+ EGLConfig config = getEglConfig(mEgl);
+ EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ mEglContext = eglCreateContext(mEgl, config, nullptr, contextAttributes);
+
mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
- ui::Size resolution = displayMode.resolution;
- resolution = limitSurfaceSize(resolution.width, resolution.height);
- // create the native surface
- sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
- resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
- ISurfaceComposerClient::eOpaque);
- SurfaceComposerClient::Transaction t;
- t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK);
- t.setLayerStack(control, ui::DEFAULT_LAYER_STACK);
+ for (size_t displayIdx = 0; displayIdx < mDisplays.size(); displayIdx++) {
+ auto& display = mDisplays[displayIdx];
+ DisplayMode displayMode;
+ const status_t error =
+ SurfaceComposerClient::getActiveDisplayMode(display.displayToken, &displayMode);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ ui::Size resolution = displayMode.resolution;
+ // Clamp each surface to max size
+ resolution = limitSurfaceSize(resolution.width, resolution.height);
+ // Create the native surface
+ display.surfaceControl =
+ session()->createSurface(String8("BootAnimation"), resolution.width,
+ resolution.height, PIXEL_FORMAT_RGB_565,
+ ISurfaceComposerClient::eOpaque);
+ // Attach surface to layerstack, and associate layerstack with physical display
+ configureDisplayAndLayerStack(display, ui::LayerStack::fromValue(displayIdx));
+ display.surface = display.surfaceControl->getSurface();
+ display.eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr);
- t.setLayer(control, 0x40000000)
- .apply();
+ EGLint w, h;
+ eglQuerySurface(mEgl, display.eglSurface, EGL_WIDTH, &w);
+ eglQuerySurface(mEgl, display.eglSurface, EGL_HEIGHT, &h);
+ if (eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface,
+ mEglContext) == EGL_FALSE) {
+ return NO_INIT;
+ }
+ display.initWidth = display.width = w;
+ display.initHeight = display.height = h;
+ mTargetInset = -1;
- sp<Surface> s = control->getSurface();
+ // Rotate the boot animation according to the value specified in the sysprop
+ // ro.bootanim.set_orientation_<display_id>. Four values are supported: ORIENTATION_0,
+ // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270.
+ // If the value isn't specified or is ORIENTATION_0, nothing will be changed.
+ // This is needed to support boot animation in orientations different from the natural
+ // device orientation. For example, on tablets that may want to keep natural orientation
+ // portrait for applications compatibility and to have the boot animation in landscape.
+ rotateAwayFromNaturalOrientationIfNeeded(display);
- // initialize opengl and egl
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(display, nullptr, nullptr);
- EGLConfig config = getEglConfig(display);
- EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
- // Initialize egl context with client version number 2.0.
- EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
- EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
- EGLint w, h;
- eglQuerySurface(display, surface, EGL_WIDTH, &w);
- eglQuerySurface(display, surface, EGL_HEIGHT, &h);
-
- if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
- return NO_INIT;
- }
-
- mDisplay = display;
- mContext = context;
- mSurface = surface;
- mInitWidth = mWidth = w;
- mInitHeight = mHeight = h;
- mFlingerSurfaceControl = control;
- mFlingerSurface = s;
- mTargetInset = -1;
-
- // Rotate the boot animation according to the value specified in the sysprop
- // ro.bootanim.set_orientation_<display_id>. Four values are supported: ORIENTATION_0,
- // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270.
- // If the value isn't specified or is ORIENTATION_0, nothing will be changed.
- // This is needed to support having boot animation in orientations different from the natural
- // device orientation. For example, on tablets that may want to keep natural orientation
- // portrait for applications compatibility and to have the boot animation in landscape.
- rotateAwayFromNaturalOrientationIfNeeded();
-
- projectSceneToWindow();
+ projectSceneToWindow(display);
+ } // end iteration over all display tokens
// Register a display event receiver
mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();
status_t status = mDisplayEventReceiver->initCheck();
SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d",
- status);
+ status);
mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
- new DisplayEventCallback(this), nullptr);
+ new DisplayEventCallback(this), nullptr);
return NO_ERROR;
}
-void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() {
+void BootAnimation::configureDisplayAndLayerStack(const Display& display,
+ ui::LayerStack layerStack) {
+ SurfaceComposerClient::Transaction t;
+ t.setDisplayLayerStack(display.displayToken, layerStack);
+ t.setLayerStack(display.surfaceControl, layerStack)
+ .setLayer(display.surfaceControl, 0x40000000)
+ .apply();
+}
+
+void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded(Display& display) {
ATRACE_CALL();
const auto orientation = parseOrientationProperty();
@@ -600,16 +620,16 @@
}
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
- std::swap(mWidth, mHeight);
- std::swap(mInitWidth, mInitHeight);
- mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight);
+ std::swap(display.width, display.height);
+ std::swap(display.initWidth, display.initHeight);
+ display.surfaceControl->updateDefaultBufferSize(display.width, display.height);
}
- Rect displayRect(0, 0, mWidth, mHeight);
- Rect layerStackRect(0, 0, mWidth, mHeight);
+ Rect displayRect(0, 0, display.width, display.height);
+ Rect layerStackRect(0, 0, display.width, display.height);
SurfaceComposerClient::Transaction t;
- t.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect);
+ t.setDisplayProjection(display.displayToken, orientation, layerStackRect, displayRect);
t.apply();
}
@@ -640,38 +660,37 @@
return ui::ROTATION_0;
}
-void BootAnimation::projectSceneToWindow() {
+void BootAnimation::projectSceneToWindow(const Display& display) {
ATRACE_CALL();
- glViewport(0, 0, mWidth, mHeight);
- glScissor(0, 0, mWidth, mHeight);
+ glViewport(0, 0, display.width, display.height);
+ glScissor(0, 0, display.width, display.height);
}
-void BootAnimation::resizeSurface(int newWidth, int newHeight) {
+void BootAnimation::resizeSurface(int newWidth, int newHeight, Display& display) {
ATRACE_CALL();
// We assume this function is called on the animation thread.
- if (newWidth == mWidth && newHeight == mHeight) {
+ if (newWidth == display.width && newHeight == display.height) {
return;
}
- SLOGV("Resizing the boot animation surface to %d %d", newWidth, newHeight);
- eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(mDisplay, mSurface);
+ eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(mEgl, display.eglSurface);
const auto limitedSize = limitSurfaceSize(newWidth, newHeight);
- mWidth = limitedSize.width;
- mHeight = limitedSize.height;
+ display.width = limitedSize.width;
+ display.height = limitedSize.height;
- mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight);
- EGLConfig config = getEglConfig(mDisplay);
- EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr);
- if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) {
- SLOGE("Can't make the new surface current. Error %d", eglGetError());
+ display.surfaceControl->updateDefaultBufferSize(display.width, display.height);
+ EGLConfig config = getEglConfig(mEgl);
+ EGLSurface eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr);
+ if (eglMakeCurrent(mEgl, eglSurface, eglSurface, mEglContext) == EGL_FALSE) {
+ SLOGE("Can't make the new eglSurface current. Error %d", eglGetError());
return;
}
- projectSceneToWindow();
+ projectSceneToWindow(display);
- mSurface = surface;
+ display.eglSurface = eglSurface;
}
bool BootAnimation::preloadAnimation() {
@@ -801,24 +820,26 @@
// animation.
if (mZipFileName.empty()) {
ALOGD("No animation file");
- result = android();
+ result = android(mDisplays.front());
} else {
result = movie();
}
mCallbacks->shutdown();
- eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroyContext(mDisplay, mContext);
- eglDestroySurface(mDisplay, mSurface);
- mFlingerSurface.clear();
- mFlingerSurfaceControl.clear();
- eglTerminate(mDisplay);
+ eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(mEgl, mEglContext);
+ for (auto& display : mDisplays) {
+ eglDestroySurface(mEgl, display.eglSurface);
+ display.surface.clear();
+ display.surfaceControl.clear();
+ }
+ eglTerminate(mEgl);
eglReleaseThread();
IPCThreadState::self()->stopProcess();
return result;
}
-bool BootAnimation::android() {
+bool BootAnimation::android(const Display& display) {
ATRACE_CALL();
glActiveTexture(GL_TEXTURE0);
@@ -836,7 +857,7 @@
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
- eglSwapBuffers(mDisplay, mSurface);
+ eglSwapBuffers(mEgl, display.eglSurface);
// Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -844,11 +865,11 @@
const nsecs_t startTime = systemTime();
do {
processDisplayEvents();
- const GLint xc = (mWidth - mAndroid[0].w) / 2;
- const GLint yc = (mHeight - mAndroid[0].h) / 2;
+ const GLint xc = (display.width - mAndroid[0].w) / 2;
+ const GLint yc = (display.height - mAndroid[0].h) / 2;
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
- glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
- updateRect.height());
+ glScissor(updateRect.left, display.height - updateRect.bottom, updateRect.width(),
+ updateRect.height());
nsecs_t now = systemTime();
double time = now - startTime;
@@ -862,14 +883,14 @@
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
- drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h);
- drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
+ drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h, display);
+ drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h, display);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
- drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
+ drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h, display);
- EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
+ EGLBoolean res = eglSwapBuffers(mEgl, display.eglSurface);
if (res == EGL_FALSE)
break;
@@ -888,7 +909,7 @@
void BootAnimation::checkExit() {
ATRACE_CALL();
- // Allow surface flinger to gracefully request shutdown
+ // Allow SurfaceFlinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");
int exitnow = atoi(value);
@@ -1034,7 +1055,8 @@
return status;
}
-void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
+void BootAnimation::drawText(const char* str, const Font& font, bool bold,
+ int* x, int* y, const Display& display) {
ATRACE_CALL();
glEnable(GL_BLEND); // Allow us to draw on top of the animation
glBindTexture(GL_TEXTURE_2D, font.texture.name);
@@ -1045,14 +1067,14 @@
const int strWidth = font.char_width * len;
if (*x == TEXT_CENTER_VALUE) {
- *x = (mWidth - strWidth) / 2;
+ *x = (display.width - strWidth) / 2;
} else if (*x < 0) {
- *x = mWidth + *x - strWidth;
+ *x = display.width + *x - strWidth;
}
if (*y == TEXT_CENTER_VALUE) {
- *y = (mHeight - font.char_height) / 2;
+ *y = (display.height - font.char_height) / 2;
} else if (*y < 0) {
- *y = mHeight + *y - font.char_height;
+ *y = display.height + *y - font.char_height;
}
for (int i = 0; i < len; i++) {
@@ -1072,7 +1094,7 @@
float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
float u1 = u0 + 1.0f / FONT_NUM_COLS;
glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
- drawTexturedQuad(*x, *y, font.char_width, font.char_height);
+ drawTexturedQuad(*x, *y, font.char_width, font.char_height, display);
*x += font.char_width;
}
@@ -1082,7 +1104,8 @@
}
// We render 12 or 24 hour time.
-void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
+void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos,
+ const Display& display) {
ATRACE_CALL();
static constexpr char TIME_FORMAT_12[] = "%l:%M";
static constexpr char TIME_FORMAT_24[] = "%H:%M";
@@ -1105,10 +1128,11 @@
char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0];
int x = xPos;
int y = yPos;
- drawText(out, font, false, &x, &y);
+ drawText(out, font, false, &x, &y, display);
}
-void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos) {
+void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos,
+ const Display& display) {
ATRACE_CALL();
static constexpr int PERCENT_LENGTH = 5;
@@ -1118,7 +1142,7 @@
sprintf(percentBuff, "%d;", percent);
int x = xPos;
int y = yPos;
- drawText(percentBuff, font, false, &x, &y);
+ drawText(percentBuff, font, false, &x, &y, display);
}
bool BootAnimation::parseAnimationDesc(Animation& animation) {
@@ -1247,8 +1271,7 @@
bool BootAnimation::preloadZip(Animation& animation) {
ATRACE_CALL();
- // read all the data structures
- const size_t pcount = animation.parts.size();
+ const size_t numParts = animation.parts.size();
void *cookie = nullptr;
ZipFileRO* zip = animation.zip;
if (!zip->startIteration(&cookie)) {
@@ -1284,8 +1307,8 @@
continue;
}
- for (size_t j = 0; j < pcount; j++) {
- if (path.string() == animation.parts[j].path.c_str()) {
+ for (size_t partIdx = 0; partIdx < numParts; partIdx++) {
+ if (path.string() == animation.parts[partIdx].path.c_str()) {
uint16_t method;
// supports only stored png files
if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr,
@@ -1293,7 +1316,7 @@
if (method == ZipFileRO::kCompressStored) {
FileMap* map = zip->createEntryFileMap(entry);
if (map) {
- Animation::Part& part(animation.parts.editItemAt(j));
+ Animation::Part& part(animation.parts.editItemAt(partIdx));
if (leaf == "audio.wav") {
// a part may have at most one audio file
part.audioData = (uint8_t *)map->getDataPtr();
@@ -1324,7 +1347,8 @@
// If there is trimData present, override the positioning defaults.
for (Animation::Part& part : animation.parts) {
const char* trimDataStr = part.trimData.c_str();
- for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
+ const size_t numFramesInPart = part.frames.size();
+ for (size_t frameIdxInPart = 0; frameIdxInPart < numFramesInPart; frameIdxInPart++) {
const char* endl = strstr(trimDataStr, "\n");
// No more trimData for this part.
if (endl == nullptr) {
@@ -1335,7 +1359,7 @@
trimDataStr = ++endl;
int width = 0, height = 0, x = 0, y = 0;
if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
- Animation::Frame& frame(part.frames.editItemAt(frameIdx));
+ Animation::Frame& frame(part.frames.editItemAt(frameIdxInPart));
frame.trimWidth = width;
frame.trimHeight = height;
frame.trimX = x;
@@ -1458,13 +1482,15 @@
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
}
-void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
+void BootAnimation::drawTexturedQuad(float xStart, float yStart,
+ float width, float height,
+ const Display& display) {
ATRACE_CALL();
// Map coordinates from screen space to world space.
- float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
- float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
- float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1);
- float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1);
+ float x0 = mapLinear(xStart, 0, display.width, -1, 1);
+ float y0 = mapLinear(yStart, 0, display.height, -1, 1);
+ float x1 = mapLinear(xStart + width, 0, display.width, -1, 1);
+ float y1 = mapLinear(yStart + height, 0, display.height, -1, 1);
// Update quad vertex positions.
quadPositions[0] = x0;
quadPositions[1] = y0;
@@ -1511,7 +1537,7 @@
bool BootAnimation::playAnimation(const Animation& animation) {
ATRACE_CALL();
- const size_t pcount = animation.parts.size();
+ const size_t numParts = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
@@ -1521,9 +1547,9 @@
int lastDisplayedProgress = 0;
int colorTransitionStart = animation.colorTransitionStart;
int colorTransitionEnd = animation.colorTransitionEnd;
- for (size_t i=0 ; i<pcount ; i++) {
- const Animation::Part& part(animation.parts[i]);
- const size_t fcount = part.frames.size();
+ for (size_t partIdx = 0; partIdx < numParts; partIdx++) {
+ const Animation::Part& part(animation.parts[partIdx]);
+ const size_t numFramesInPart = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
// Handle animation package
@@ -1535,7 +1561,9 @@
}
// process the part not only while the count allows but also if already fading
- for (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) {
+ for (int frameIdx = 0;
+ !part.count || frameIdx < part.count || fadedFramesCount > 0;
+ frameIdx++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
// It's possible that the sysprops were not loaded yet at this boot phase.
@@ -1550,12 +1578,12 @@
const int transitionLength = colorTransitionEnd - colorTransitionStart;
if (part.postDynamicColoring) {
colorTransitionStart = 0;
- colorTransitionEnd = fmin(transitionLength, fcount - 1);
+ colorTransitionEnd = fmin(transitionLength, numFramesInPart - 1);
}
}
}
- mCallbacks->playPart(i, part, r);
+ mCallbacks->playPart(partIdx, part, frameIdx);
glClearColor(
part.backgroundColor[0],
@@ -1569,11 +1597,10 @@
// For the last animation, if we have progress indicator from
// the system, display it.
- int currentProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
- bool displayProgress = animation.progressEnabled &&
- (i == (pcount -1)) && currentProgress != 0;
+ const bool displayProgress = animation.progressEnabled && (partIdx == (numParts - 1)) &&
+ android::base::GetIntProperty(PROGRESS_PROP_NAME, 0) != 0;
- for (size_t j=0 ; j<fcount ; j++) {
+ for (size_t frameIdxInPart = 0; frameIdxInPart < numFramesInPart; frameIdxInPart++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
// Color progress is
@@ -1584,21 +1611,15 @@
// - 1 for parts that come after.
float colorProgress = part.useDynamicColoring
? fmin(fmax(
- ((float)j - colorTransitionStart) /
+ (static_cast<float>(frameIdxInPart) - colorTransitionStart) /
fmax(colorTransitionEnd - colorTransitionStart, 1.0f), 0.0f), 1.0f)
: (part.postDynamicColoring ? 1 : 0);
-
processDisplayEvents();
- const double ratio_w = static_cast<double>(mWidth) / mInitWidth;
- const double ratio_h = static_cast<double>(mHeight) / mInitHeight;
- const int animationX = (mWidth - animation.width * ratio_w) / 2;
- const int animationY = (mHeight - animation.height * ratio_h) / 2;
-
- const Animation::Frame& frame(part.frames[j]);
+ const Animation::Frame& frame(part.frames[frameIdxInPart]);
nsecs_t lastFrame = systemTime();
- if (r > 0) {
+ if (frameIdx > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
if (part.count != 1) {
@@ -1611,17 +1632,6 @@
initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
}
- const int trimWidth = frame.trimWidth * ratio_w;
- const int trimHeight = frame.trimHeight * ratio_h;
- const int trimX = frame.trimX * ratio_w;
- const int trimY = frame.trimY * ratio_h;
- const int xc = animationX + trimX;
- const int yc = animationY + trimY;
- glClear(GL_COLOR_BUFFER_BIT);
- // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
- // which is equivalent to mHeight - (yc + frame.trimHeight)
- const int frameDrawY = mHeight - (yc + trimHeight);
-
float fade = 0;
// if the part hasn't been stopped yet then continue fading if necessary
if (exitPending() && part.hasFadingPhase()) {
@@ -1630,40 +1640,66 @@
fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
}
}
- glUseProgram(mImageShader);
- glUniform1i(mImageTextureLocation, 0);
- glUniform1f(mImageFadeLocation, fade);
- if (animation.dynamicColoringEnabled) {
- glUniform1f(mImageColorProgressLocation, colorProgress);
- }
- glEnable(GL_BLEND);
- drawTexturedQuad(xc, frameDrawY, trimWidth, trimHeight);
- glDisable(GL_BLEND);
- if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
- drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
- }
+ // Draw the current frame's texture on every physical display that is enabled.
+ for (const auto& display : mDisplays) {
+ eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface, mEglContext);
- if (displayProgress) {
- int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
- // In case the new progress jumped suddenly, still show an
- // increment of 1.
- if (lastDisplayedProgress != 100) {
- // Artificially sleep 1/10th a second to slow down the animation.
- usleep(100000);
- if (lastDisplayedProgress < newProgress) {
- lastDisplayedProgress++;
- }
+ const double ratioW =
+ static_cast<double>(display.width) / display.initWidth;
+ const double ratioH =
+ static_cast<double>(display.height) / display.initHeight;
+ const int animationX = (display.width - animation.width * ratioW) / 2;
+ const int animationY = (display.height - animation.height * ratioH) / 2;
+
+ const int trimWidth = frame.trimWidth * ratioW;
+ const int trimHeight = frame.trimHeight * ratioH;
+ const int trimX = frame.trimX * ratioW;
+ const int trimY = frame.trimY * ratioH;
+ const int xc = animationX + trimX;
+ const int yc = animationY + trimY;
+ projectSceneToWindow(display);
+ handleViewport(frameDuration, display);
+ glClear(GL_COLOR_BUFFER_BIT);
+ // specify the y center as ceiling((height - frame.trimHeight) / 2)
+ // which is equivalent to height - (yc + frame.trimHeight)
+ const int frameDrawY = display.height - (yc + trimHeight);
+
+ glUseProgram(mImageShader);
+ glUniform1i(mImageTextureLocation, 0);
+ glUniform1f(mImageFadeLocation, fade);
+ if (animation.dynamicColoringEnabled) {
+ glUniform1f(mImageColorProgressLocation, colorProgress);
}
- // Put the progress percentage right below the animation.
- int posY = animation.height / 3;
- int posX = TEXT_CENTER_VALUE;
- drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY);
+ glEnable(GL_BLEND);
+ drawTexturedQuad(xc, frameDrawY, trimWidth, trimHeight, display);
+ glDisable(GL_BLEND);
+
+ if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
+ drawClock(animation.clockFont, part.clockPosX, part.clockPosY, display);
+ }
+
+ if (displayProgress) {
+ int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);
+ // In case the new progress jumped suddenly, still show an
+ // increment of 1.
+ if (lastDisplayedProgress != 100) {
+ // Artificially sleep 1/10th a second to slow down the animation.
+ usleep(100000);
+ if (lastDisplayedProgress < newProgress) {
+ lastDisplayedProgress++;
+ }
+ }
+ // Put the progress percentage right below the animation.
+ int posY = animation.height / 3;
+ int posX = TEXT_CENTER_VALUE;
+ drawProgress(lastDisplayedProgress,
+ animation.progressFont, posX, posY, display);
+ }
+
+ eglSwapBuffers(mEgl, display.eglSurface);
}
- handleViewport(frameDuration);
-
- eglSwapBuffers(mDisplay, mSurface);
nsecs_t now = systemTime();
nsecs_t delay = frameDuration - (now - lastFrame);
@@ -1709,9 +1745,7 @@
// Free textures created for looping parts now that the animation is done.
for (const Animation::Part& part : animation.parts) {
if (part.count != 1) {
- const size_t fcount = part.frames.size();
- for (size_t j = 0; j < fcount; j++) {
- const Animation::Frame& frame(part.frames[j]);
+ for (const auto& frame : part.frames) {
glDeleteTextures(1, &frame.tid);
}
}
@@ -1730,16 +1764,17 @@
mLooper->pollOnce(0);
}
-void BootAnimation::handleViewport(nsecs_t timestep) {
+void BootAnimation::handleViewport(nsecs_t timestep, const Display& display) {
ATRACE_CALL();
- if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
+ if (mShuttingDown || !display.surfaceControl || mTargetInset == 0) {
return;
}
if (mTargetInset < 0) {
// Poll the amount for the top display inset. This will return -1 until persistent properties
// have been loaded.
- mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top",
- -1 /* default */, -1 /* min */, mHeight / 2 /* max */);
+ mTargetInset =
+ android::base::GetIntProperty("persist.sys.displayinset.top", -1 /* default */,
+ -1 /* min */, display.height / 2 /* max */);
}
if (mTargetInset <= 0) {
return;
@@ -1751,19 +1786,27 @@
int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset;
SurfaceComposerClient::Transaction()
- .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight))
+ .setCrop(display.surfaceControl,
+ Rect(0, interpolatedInset, display.width, display.height))
.apply();
} else {
// At the end of the animation, we switch to the viewport that DisplayManager will apply
// later. This changes the coordinate system, and means we must move the surface up by
// the inset amount.
- Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
- Rect displayRect(0, mTargetInset, mWidth, mHeight);
-
+ Rect layerStackRect(0, 0,
+ display.width,
+ display.height - mTargetInset);
+ Rect displayRect(0, mTargetInset,
+ display.width,
+ display.height);
SurfaceComposerClient::Transaction t;
- t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
- .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
- t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, layerStackRect, displayRect);
+ t.setPosition(display.surfaceControl, 0, -mTargetInset)
+ .setCrop(display.surfaceControl,
+ Rect(0, mTargetInset,
+ display.width,
+ display.height));
+ t.setDisplayProjection(display.displayToken,
+ ui::ROTATION_0, layerStackRect, displayRect);
t.apply();
mTargetInset = mCurrentInset = 0;
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 8683b71..0a05746 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -31,6 +31,7 @@
#include <binder/IBinder.h>
#include <ui/Rotation.h>
+#include <ui/LayerStack.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
@@ -119,6 +120,18 @@
float endColors[4][3]; // End colors of dynamic color transition.
};
+ // Collects all attributes that must be tracked per physical display.
+ struct Display {
+ int width;
+ int height;
+ int initWidth;
+ int initHeight;
+ EGLDisplay eglSurface;
+ sp<IBinder> displayToken;
+ sp<SurfaceControl> surfaceControl;
+ sp<Surface> surface;
+ };
+
// All callbacks will be called from this class's internal thread.
class Callbacks : public RefBase {
public:
@@ -181,14 +194,18 @@
bool premultiplyAlpha = true);
status_t initFont(Font* font, const char* fallback);
void initShaders();
- bool android();
+ bool android(const Display& display);
+ status_t initDisplaysAndSurfaces();
bool movie();
- void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
- void drawClock(const Font& font, const int xPos, const int yPos);
- void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
+ void drawText(const char* str, const Font& font, bool bold,
+ int* x, int* y, const Display& display);
+ void drawClock(const Font& font, const int xPos, const int yPos, const Display& display);
+ void drawProgress(int percent, const Font& font,
+ const int xPos, const int yPos, const Display& display);
void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
const Animation::Part& part, int fadedFramesCount);
- void drawTexturedQuad(float xStart, float yStart, float width, float height);
+ void drawTexturedQuad(float xStart, float yStart,
+ float width, float height, const Display& display);
bool validClock(const Animation::Part& part);
Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&);
@@ -200,36 +217,31 @@
bool preloadAnimation();
EGLConfig getEglConfig(const EGLDisplay&);
ui::Size limitSurfaceSize(int width, int height) const;
- void resizeSurface(int newWidth, int newHeight);
- void projectSceneToWindow();
- void rotateAwayFromNaturalOrientationIfNeeded();
+ void resizeSurface(int newWidth, int newHeight, Display& display);
+ void projectSceneToWindow(const Display& display);
+ void rotateAwayFromNaturalOrientationIfNeeded(Display& display);
ui::Rotation parseOrientationProperty();
+ void configureDisplayAndLayerStack(const Display& display, ui::LayerStack layerStack);
bool shouldStopPlayingPart(const Animation::Part& part, int fadedFramesCount,
int lastDisplayedProgress);
void checkExit();
- void handleViewport(nsecs_t timestep);
+ void handleViewport(nsecs_t timestep, const Display& display);
void initDynamicColors();
sp<SurfaceComposerClient> mSession;
AssetManager mAssets;
Texture mAndroid[2];
- int mWidth;
- int mHeight;
- int mInitWidth;
- int mInitHeight;
int mMaxWidth = 0;
int mMaxHeight = 0;
int mCurrentInset;
int mTargetInset;
bool mUseNpotTextures = false;
- EGLDisplay mDisplay;
- EGLDisplay mContext;
- EGLDisplay mSurface;
- sp<IBinder> mDisplayToken;
- sp<SurfaceControl> mFlingerSurfaceControl;
- sp<Surface> mFlingerSurface;
+ EGLDisplay mEgl;
+ EGLDisplay mEglContext;
+ // Per-Display Attributes (to support multi-display)
+ std::vector<Display> mDisplays;
bool mClockEnabled;
bool mTimeIsAccurate;
bool mTimeFormat12Hour;
diff --git a/cmds/bootanimation/bootanimation_flags.aconfig b/cmds/bootanimation/bootanimation_flags.aconfig
new file mode 100644
index 0000000..04837b9
--- /dev/null
+++ b/cmds/bootanimation/bootanimation_flags.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.graphics.bootanimation.flags"
+container: "system"
+
+flag {
+ name: "multidisplay"
+ namespace: "bootanimation"
+ description: "Enable boot animation on multiple displays (e.g. foldables)"
+ bug: "335406617"
+ is_fixed_read_only: true
+}
+
+
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index e86f814..b0ba019 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -21,18 +21,19 @@
* header := magic version target_crc overlay_crc fulfilled_policies
* enforce_overlayable target_path overlay_path overlay_name
* debug_info
- * data := data_header target_entry* target_inline_entry*
- target_inline_entry_value* config* overlay_entry* string_pool
+ * data := data_header target_entries target_inline_entries
+ target_inline_entry_value* config* overlay_entries string_pool
* data_header := target_entry_count target_inline_entry_count
target_inline_entry_value_count config_count overlay_entry_count
* string_pool_index
- * target_entry := target_id overlay_id
- * target_inline_entry := target_id start_value_index value_count
+ * target_entries := target_id* overlay_id*
+ * target_inline_entries := target_id* target_inline_value_header*
+ * target_inline_value_header := start_value_index value_count
* target_inline_entry_value := config_index Res_value::size padding(1) Res_value::type
* Res_value::value
* config := target_id Res_value::size padding(1) Res_value::type
* Res_value::value
- * overlay_entry := overlay_id target_id
+ * overlay_entries := overlay_id* target_id*
*
* debug_info := string
* enforce_overlayable := <uint32_t>
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 8976924..00ef0c7 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -66,43 +66,57 @@
void BinaryStreamVisitor::visit(const IdmapData& data) {
for (const auto& target_entry : data.GetTargetEntries()) {
Write32(target_entry.target_id);
+ }
+ for (const auto& target_entry : data.GetTargetEntries()) {
Write32(target_entry.overlay_id);
}
- static constexpr uint16_t kValueSize = 8U;
- std::vector<std::pair<ConfigDescription, TargetValue>> target_values;
- target_values.reserve(data.GetHeader()->GetTargetInlineEntryValueCount());
- for (const auto& target_entry : data.GetTargetInlineEntries()) {
- Write32(target_entry.target_id);
- Write32(target_values.size());
- Write32(target_entry.values.size());
- target_values.insert(
- target_values.end(), target_entry.values.begin(), target_entry.values.end());
+ uint32_t current_inline_entry_values_count = 0;
+ for (const auto& target_inline_entry : data.GetTargetInlineEntries()) {
+ Write32(target_inline_entry.target_id);
+ }
+ for (const auto& target_inline_entry : data.GetTargetInlineEntries()) {
+ Write32(current_inline_entry_values_count);
+ Write32(target_inline_entry.values.size());
+ current_inline_entry_values_count += target_inline_entry.values.size();
}
std::vector<ConfigDescription> configs;
configs.reserve(data.GetHeader()->GetConfigCount());
- for (const auto& target_entry_value : target_values) {
- auto config_it = find(configs.begin(), configs.end(), target_entry_value.first);
- if (config_it != configs.end()) {
- Write32(config_it - configs.begin());
- } else {
- Write32(configs.size());
- configs.push_back(target_entry_value.first);
+ for (const auto& target_entry : data.GetTargetInlineEntries()) {
+ for (const auto& target_entry_value : target_entry.values) {
+ auto config_it = std::find(configs.begin(), configs.end(), target_entry_value.first);
+ if (config_it != configs.end()) {
+ Write32(config_it - configs.begin());
+ } else {
+ Write32(configs.size());
+ configs.push_back(target_entry_value.first);
+ }
+ // We're writing a Res_value entry here, and the first 3 bytes of that are
+ // sizeof() + a padding 0 byte
+ static constexpr decltype(android::Res_value::size) kSize = sizeof(android::Res_value);
+ Write16(kSize);
+ Write8(0U);
+ Write8(target_entry_value.second.data_type);
+ Write32(target_entry_value.second.data_value);
}
- Write16(kValueSize);
- Write8(0U); // padding
- Write8(target_entry_value.second.data_type);
- Write32(target_entry_value.second.data_value);
}
- for( auto& cd : configs) {
- cd.swapHtoD();
- stream_.write(reinterpret_cast<char*>(&cd), sizeof(cd));
+ if (!configs.empty()) {
+ stream_.write(reinterpret_cast<const char*>(&configs.front()),
+ sizeof(configs.front()) * configs.size());
+ if (configs.size() >= 100) {
+ // Let's write a message to future us so that they know when to replace the linear search
+ // in `configs` vector with something more efficient.
+ LOG(WARNING) << "Idmap got " << configs.size()
+ << " configurations, time to fix the bruteforce search";
+ }
}
for (const auto& overlay_entry : data.GetOverlayEntries()) {
Write32(overlay_entry.overlay_id);
+ }
+ for (const auto& overlay_entry : data.GetOverlayEntries()) {
Write32(overlay_entry.target_id);
}
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 12d9dd9..7680109 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -204,73 +204,91 @@
}
// Read the mapping of target resource id to overlay resource value.
+ data->target_entries_.resize(data->header_->GetTargetEntryCount());
for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) {
- TargetEntry target_entry{};
- if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &target_entry.overlay_id)) {
+ if (!Read32(stream, &data->target_entries_[i].target_id)) {
return nullptr;
}
- data->target_entries_.emplace_back(target_entry);
+ }
+ for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) {
+ if (!Read32(stream, &data->target_entries_[i].overlay_id)) {
+ return nullptr;
+ }
}
// Read the mapping of target resource id to inline overlay values.
- std::vector<std::tuple<TargetInlineEntry, uint32_t, uint32_t>> target_inline_entries;
+ struct TargetInlineEntryHeader {
+ ResourceId target_id;
+ uint32_t values_offset;
+ uint32_t values_count;
+ };
+ std::vector<TargetInlineEntryHeader> target_inline_entries(
+ data->header_->GetTargetInlineEntryCount());
for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
- TargetInlineEntry target_entry{};
- uint32_t entry_offset;
- uint32_t entry_count;
- if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &entry_offset)
- || !Read32(stream, &entry_count)) {
+ if (!Read32(stream, &target_inline_entries[i].target_id)) {
return nullptr;
}
- target_inline_entries.emplace_back(target_entry, entry_offset, entry_count);
+ }
+ for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
+ if (!Read32(stream, &target_inline_entries[i].values_offset) ||
+ !Read32(stream, &target_inline_entries[i].values_count)) {
+ return nullptr;
+ }
}
// Read the inline overlay resource values
- std::vector<std::pair<uint32_t, TargetValue>> target_values;
- uint8_t unused1;
- uint16_t unused2;
- for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
+ struct TargetValueHeader {
uint32_t config_index;
- if (!Read32(stream, &config_index)) {
+ DataType data_type;
+ DataValue data_value;
+ };
+ std::vector<TargetValueHeader> target_values(data->header_->GetTargetInlineEntryValueCount());
+ for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
+ auto& value = target_values[i];
+ if (!Read32(stream, &value.config_index)) {
return nullptr;
}
- TargetValue value;
- if (!Read16(stream, &unused2)
- || !Read8(stream, &unused1)
- || !Read8(stream, &value.data_type)
- || !Read32(stream, &value.data_value)) {
+ // skip the padding
+ stream.seekg(3, std::ios::cur);
+ if (!Read8(stream, &value.data_type) || !Read32(stream, &value.data_value)) {
return nullptr;
}
- target_values.emplace_back(config_index, value);
}
// Read the configurations
- std::vector<ConfigDescription> configurations;
- for (size_t i = 0; i < data->header_->GetConfigCount(); i++) {
- ConfigDescription cd;
- if (!stream.read(reinterpret_cast<char*>(&cd), sizeof(ConfigDescription))) {
+ std::vector<ConfigDescription> configurations(data->header_->GetConfigCount());
+ if (!configurations.empty()) {
+ if (!stream.read(reinterpret_cast<char*>(&configurations.front()),
+ sizeof(configurations.front()) * configurations.size())) {
return nullptr;
}
- configurations.emplace_back(cd);
}
// Construct complete target inline entries
- for (auto [target_entry, entry_offset, entry_count] : target_inline_entries) {
- for(size_t i = 0; i < entry_count; i++) {
- const auto& target_value = target_values[entry_offset + i];
- const auto& config = configurations[target_value.first];
- target_entry.values[config] = target_value.second;
+ data->target_inline_entries_.reserve(target_inline_entries.size());
+ for (auto&& entry_header : target_inline_entries) {
+ TargetInlineEntry& entry = data->target_inline_entries_.emplace_back();
+ entry.target_id = entry_header.target_id;
+ for (size_t i = 0; i < entry_header.values_count; i++) {
+ const auto& value_header = target_values[entry_header.values_offset + i];
+ const auto& config = configurations[value_header.config_index];
+ auto& value = entry.values[config];
+ value.data_type = value_header.data_type;
+ value.data_value = value_header.data_value;
}
- data->target_inline_entries_.emplace_back(target_entry);
}
// Read the mapping of overlay resource id to target resource id.
+ data->overlay_entries_.resize(data->header_->GetOverlayEntryCount());
for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) {
- OverlayEntry overlay_entry{};
- if (!Read32(stream, &overlay_entry.overlay_id) || !Read32(stream, &overlay_entry.target_id)) {
+ if (!Read32(stream, &data->overlay_entries_[i].overlay_id)) {
return nullptr;
}
- data->overlay_entries_.emplace_back(overlay_entry);
+ }
+ for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) {
+ if (!Read32(stream, &data->overlay_entries_[i].target_id)) {
+ return nullptr;
+ }
}
// Read raw string pool bytes.
@@ -320,7 +338,7 @@
std::unique_ptr<IdmapData> data(new IdmapData());
data->string_pool_data_ = std::string(resource_mapping.GetStringPoolData());
uint32_t inline_value_count = 0;
- std::set<std::string> config_set;
+ std::set<std::string_view> config_set;
for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
if (auto overlay_resource = std::get_if<ResourceId>(&mapping.second)) {
data->target_entries_.push_back({mapping.first, *overlay_resource});
@@ -329,7 +347,9 @@
for (const auto& [config, value] : std::get<ConfigMap>(mapping.second)) {
config_set.insert(config);
ConfigDescription cd;
- ConfigDescription::Parse(config, &cd);
+ if (!ConfigDescription::Parse(config, &cd)) {
+ return Error("failed to parse configuration string '%s'", config.c_str());
+ }
values[cd] = value;
inline_value_count++;
}
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index c85619c..1b656e8 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -68,7 +68,7 @@
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
ASSERT_EQ(header->GetMagic(), 0x504d4449U);
- ASSERT_EQ(header->GetVersion(), 0x09U);
+ ASSERT_EQ(header->GetVersion(), 10);
ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
@@ -143,7 +143,7 @@
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 10);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies);
@@ -204,7 +204,7 @@
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 10);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 68164e2..7fae1c6 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -64,7 +64,7 @@
(*idmap)->accept(&visitor);
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000009 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "0000000a version\n", stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
stream.str());
@@ -113,7 +113,7 @@
(*idmap)->accept(&visitor);
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000009 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "0000000a version\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str());
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index bf01c32..2b4ebd1 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -34,7 +34,7 @@
0x49, 0x44, 0x4d, 0x50,
// 0x4: version
- 0x09, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00,
// 0x8: target crc
0x34, 0x12, 0x00, 0x00,
@@ -95,19 +95,15 @@
// TARGET ENTRIES
// 0x6c: target id (0x7f020000)
0x00, 0x00, 0x02, 0x7f,
-
- // 0x70: overlay_id (0x7f020000)
- 0x00, 0x00, 0x02, 0x7f,
-
- // 0x74: target id (0x7f030000)
+ // 0x70: target id (0x7f030000)
0x00, 0x00, 0x03, 0x7f,
-
- // 0x78: overlay_id (0x7f030000)
- 0x00, 0x00, 0x03, 0x7f,
-
- // 0x7c: target id (0x7f030002)
+ // 0x74: target id (0x7f030002)
0x02, 0x00, 0x03, 0x7f,
+ // 0x78: overlay_id (0x7f020000)
+ 0x00, 0x00, 0x02, 0x7f,
+ // 0x7c: overlay_id (0x7f030000)
+ 0x00, 0x00, 0x03, 0x7f,
// 0x80: overlay_id (0x7f030001)
0x01, 0x00, 0x03, 0x7f,
@@ -178,16 +174,20 @@
// 0xe1: padding
0x00, 0x00, 0x00,
-
// OVERLAY ENTRIES
- // 0xe4: 0x7f020000 -> 0x7f020000
- 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
+ // 0xe4: 0x7f020000 -> ...
+ 0x00, 0x00, 0x02, 0x7f,
+ // 0xe8: 0x7f030000 -> ...
+ 0x00, 0x00, 0x03, 0x7f,
+ // 0xec: 0x7f030001 -> ...
+ 0x01, 0x00, 0x03, 0x7f,
- // 0xec: 0x7f030000 -> 0x7f030000
- 0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
-
- // 0xf4: 0x7f030001 -> 0x7f030002
- 0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
+ // 0xf0: ... -> 0x7f020000
+ 0x00, 0x00, 0x02, 0x7f,
+ // 0xf4: ... -> 0x7f030000
+ 0x00, 0x00, 0x03, 0x7f,
+ // 0xf8: ... -> 0x7f030002
+ 0x02, 0x00, 0x03, 0x7f,
// 0xfc: string pool
// string length,
diff --git a/core/api/current.txt b/core/api/current.txt
index ca45d1b..7a07d58 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9834,6 +9834,7 @@
public final class AssociationInfo implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.companion.AssociatedDevice getAssociatedDevice();
+ method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon();
method @Nullable public android.net.MacAddress getDeviceMacAddress();
method @Nullable public String getDeviceProfile();
method @Nullable public CharSequence getDisplayName();
@@ -9847,6 +9848,7 @@
public final class AssociationRequest implements android.os.Parcelable {
method public int describeContents();
+ method @FlaggedApi("android.companion.association_device_icon") @Nullable public android.graphics.drawable.Icon getDeviceIcon();
method @Nullable public String getDeviceProfile();
method @Nullable public CharSequence getDisplayName();
method public boolean isForceConfirmation();
@@ -9866,6 +9868,7 @@
ctor public AssociationRequest.Builder();
method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>);
method @NonNull public android.companion.AssociationRequest build();
+ method @FlaggedApi("android.companion.association_device_icon") @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setDeviceIcon(@NonNull android.graphics.drawable.Icon);
method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String);
method @NonNull public android.companion.AssociationRequest.Builder setDisplayName(@NonNull CharSequence);
method @NonNull @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public android.companion.AssociationRequest.Builder setForceConfirmation(boolean);
@@ -22601,6 +22604,7 @@
method public void sendEvent(int, int, @Nullable byte[]) throws android.media.MediaCasException;
method public void setEventListener(@Nullable android.media.MediaCas.EventListener, @Nullable android.os.Handler);
method public void setPrivateData(@NonNull byte[]) throws android.media.MediaCasException;
+ method @FlaggedApi("com.android.media.flags.update_client_profile_priority") public boolean updateResourcePriority(int, int);
field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
@@ -49254,6 +49258,7 @@
field public static final String ARG_PROTOCOL = "android.arg.protocol";
field public static final String ARG_QUANTITY = "android.arg.quantity";
field public static final String ARG_QUERY_STRING = "android.arg.query_string";
+ field @FlaggedApi("com.android.text.flags.tts_span_duration") public static final String ARG_SECONDS = "android.arg.seconds";
field public static final String ARG_TEXT = "android.arg.text";
field public static final String ARG_UNIT = "android.arg.unit";
field public static final String ARG_USERNAME = "android.arg.username";
@@ -49290,6 +49295,7 @@
field public static final String TYPE_DATE = "android.type.date";
field public static final String TYPE_DECIMAL = "android.type.decimal";
field public static final String TYPE_DIGITS = "android.type.digits";
+ field @FlaggedApi("com.android.text.flags.tts_span_duration") public static final String TYPE_DURATION = "android.type.duration";
field public static final String TYPE_ELECTRONIC = "android.type.electronic";
field public static final String TYPE_FRACTION = "android.type.fraction";
field public static final String TYPE_MEASURE = "android.type.measure";
@@ -49349,6 +49355,13 @@
method public android.text.style.TtsSpan.DigitsBuilder setDigits(String);
}
+ @FlaggedApi("com.android.text.flags.tts_span_duration") public static class TtsSpan.DurationBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.DurationBuilder> {
+ ctor @FlaggedApi("com.android.text.flags.tts_span_duration") public TtsSpan.DurationBuilder();
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setHours(int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setMinutes(int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.DurationBuilder setSeconds(int);
+ }
+
public static class TtsSpan.ElectronicBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.ElectronicBuilder> {
ctor public TtsSpan.ElectronicBuilder();
method public android.text.style.TtsSpan.ElectronicBuilder setDomain(String);
@@ -49431,6 +49444,7 @@
ctor public TtsSpan.TimeBuilder(int, int);
method public android.text.style.TtsSpan.TimeBuilder setHours(int);
method public android.text.style.TtsSpan.TimeBuilder setMinutes(int);
+ method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(int);
}
public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.VerbatimBuilder> {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 287e787..4d1a423 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -321,7 +321,7 @@
package android.net.wifi {
public final class WifiMigration {
- method @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static int migrateLegacyKeystoreToWifiBlobstore();
+ method @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static void migrateLegacyKeystoreToWifiBlobstore(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION = 2; // 0x2
field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE = 0; // 0x0
field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 76e9ca0..5e4485c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -914,6 +914,7 @@
ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo);
method @NonNull public android.companion.AssociationInfo build();
method @NonNull public android.companion.AssociationInfo.Builder setAssociatedDevice(@Nullable android.companion.AssociatedDevice);
+ method @FlaggedApi("android.companion.association_device_icon") @NonNull public android.companion.AssociationInfo.Builder setDeviceIcon(@Nullable android.graphics.drawable.Icon);
method @NonNull public android.companion.AssociationInfo.Builder setDeviceMacAddress(@Nullable android.net.MacAddress);
method @NonNull public android.companion.AssociationInfo.Builder setDeviceProfile(@Nullable String);
method @NonNull public android.companion.AssociationInfo.Builder setDisplayName(@Nullable CharSequence);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 2fa418a..1265de1 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -647,7 +647,6 @@
java_library {
name: "protolog-lib",
- platform_apis: true,
srcs: [
"com/android/internal/protolog/ProtoLogImpl.java",
"com/android/internal/protolog/ProtoLogViewerConfigReader.java",
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 8bb2857..5bc7de9 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -84,19 +84,25 @@
* @attr ref android.R.styleable#AccessibilityService_accessibilityEventTypes
* @attr ref android.R.styleable#AccessibilityService_accessibilityFeedbackType
* @attr ref android.R.styleable#AccessibilityService_accessibilityFlags
+ * @attr ref android.R.styleable#AccessibilityService_animatedImageDrawable
+ * @attr ref android.R.styleable#AccessibilityService_canControlMagnification
+ * @attr ref android.R.styleable#AccessibilityService_canPerformGestures
* @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
+ * @attr ref android.R.styleable#AccessibilityService_canRequestFingerprintGestures
* @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
* @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
- * @attr ref android.R.styleable#AccessibilityService_intro
+ * @attr ref android.R.styleable#AccessibilityService_canTakeScreenshot
* @attr ref android.R.styleable#AccessibilityService_description
- * @attr ref android.R.styleable#AccessibilityService_summary
+ * @attr ref android.R.styleable#AccessibilityService_htmlDescription
+ * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
+ * @attr ref android.R.styleable#AccessibilityService_intro
+ * @attr ref android.R.styleable#AccessibilityService_isAccessibilityTool
+ * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
* @attr ref android.R.styleable#AccessibilityService_notificationTimeout
* @attr ref android.R.styleable#AccessibilityService_packageNames
* @attr ref android.R.styleable#AccessibilityService_settingsActivity
+ * @attr ref android.R.styleable#AccessibilityService_summary
* @attr ref android.R.styleable#AccessibilityService_tileService
- * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
- * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout
- * @attr ref android.R.styleable#AccessibilityService_canTakeScreenshot
* @see AccessibilityService
* @see android.view.accessibility.AccessibilityEvent
* @see android.view.accessibility.AccessibilityManager
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c1c96ea..014e4660 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -285,6 +285,14 @@
public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze";
/**
+ * Command for {@link #sendWallpaperCommand}: in sendWallpaperCommand put extra to this command
+ * to give the bounds of space between the bottom of notifications and the top of shortcuts
+ * @hide
+ */
+ public static final String COMMAND_LOCKSCREEN_LAYOUT_CHANGED =
+ "android.wallpaper.lockscreen_layout_changed";
+
+ /**
* Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
* @hide
*/
diff --git a/core/java/android/app/wearable/flags.aconfig b/core/java/android/app/wearable/flags.aconfig
index b68bafe..534f461 100644
--- a/core/java/android/app/wearable/flags.aconfig
+++ b/core/java/android/app/wearable/flags.aconfig
@@ -38,4 +38,12 @@
namespace: "machine_learning"
description: "This flag enables the APIs related to hotword in WearableSensingManager and WearableSensingService."
bug: "310055381"
+}
+
+flag {
+ name: "enable_concurrent_wearable_connections"
+ is_exported: true
+ namespace: "machine_learning"
+ description: "This flag enables the APIs for providing multiple concurrent connections to the WearableSensingService."
+ bug: "358133158"
}
\ No newline at end of file
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index b4b96e2..7f30d7c 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -22,6 +22,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.graphics.drawable.Icon;
import android.net.MacAddress;
import android.os.Parcel;
import android.os.Parcelable;
@@ -86,6 +87,11 @@
private final int mSystemDataSyncFlags;
/**
+ * A device icon displayed on a selfManaged association dialog.
+ */
+ private final Icon mDeviceIcon;
+
+ /**
* Creates a new Association.
*
* @hide
@@ -95,7 +101,7 @@
@Nullable CharSequence displayName, @Nullable String deviceProfile,
@Nullable AssociatedDevice associatedDevice, boolean selfManaged,
boolean notifyOnDeviceNearby, boolean revoked, boolean pending, long timeApprovedMs,
- long lastTimeConnectedMs, int systemDataSyncFlags) {
+ long lastTimeConnectedMs, int systemDataSyncFlags, @Nullable Icon deviceIcon) {
if (id <= 0) {
throw new IllegalArgumentException("Association ID should be greater than 0");
}
@@ -119,6 +125,7 @@
mTimeApprovedMs = timeApprovedMs;
mLastTimeConnectedMs = lastTimeConnectedMs;
mSystemDataSyncFlags = systemDataSyncFlags;
+ mDeviceIcon = deviceIcon;
}
/**
@@ -278,6 +285,20 @@
}
/**
+ * Get the device icon of the associated device. The device icon represents the device type.
+ *
+ * @return the device icon, or {@code null} if no device icon is has been set for the
+ * associated device.
+ *
+ * @see AssociationRequest.Builder#setDeviceIcon(Icon)
+ */
+ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+ @Nullable
+ public Icon getDeviceIcon() {
+ return mDeviceIcon;
+ }
+
+ /**
* Utility method for checking if the association represents a device with the given MAC
* address.
*
@@ -370,14 +391,16 @@
&& Objects.equals(mDisplayName, that.mDisplayName)
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
&& Objects.equals(mAssociatedDevice, that.mAssociatedDevice)
- && mSystemDataSyncFlags == that.mSystemDataSyncFlags;
+ && mSystemDataSyncFlags == that.mSystemDataSyncFlags
+ && (mDeviceIcon == null ? that.mDeviceIcon == null
+ : mDeviceIcon.sameAs(that.mDeviceIcon));
}
@Override
public int hashCode() {
return Objects.hash(mId, mUserId, mPackageName, mTag, mDeviceMacAddress, mDisplayName,
mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked,
- mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags);
+ mPending, mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags, mDeviceIcon);
}
@Override
@@ -402,6 +425,12 @@
dest.writeLong(mTimeApprovedMs);
dest.writeLong(mLastTimeConnectedMs);
dest.writeInt(mSystemDataSyncFlags);
+ if (mDeviceIcon != null) {
+ dest.writeInt(1);
+ mDeviceIcon.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
}
private AssociationInfo(@NonNull Parcel in) {
@@ -420,6 +449,11 @@
mTimeApprovedMs = in.readLong();
mLastTimeConnectedMs = in.readLong();
mSystemDataSyncFlags = in.readInt();
+ if (in.readInt() == 1) {
+ mDeviceIcon = Icon.CREATOR.createFromParcel(in);
+ } else {
+ mDeviceIcon = null;
+ }
}
@NonNull
@@ -459,6 +493,7 @@
private long mTimeApprovedMs;
private long mLastTimeConnectedMs;
private int mSystemDataSyncFlags;
+ private Icon mDeviceIcon;
/** @hide */
@TestApi
@@ -486,6 +521,7 @@
mTimeApprovedMs = info.mTimeApprovedMs;
mLastTimeConnectedMs = info.mLastTimeConnectedMs;
mSystemDataSyncFlags = info.mSystemDataSyncFlags;
+ mDeviceIcon = info.mDeviceIcon;
}
/**
@@ -510,6 +546,7 @@
mTimeApprovedMs = info.mTimeApprovedMs;
mLastTimeConnectedMs = info.mLastTimeConnectedMs;
mSystemDataSyncFlags = info.mSystemDataSyncFlags;
+ mDeviceIcon = info.mDeviceIcon;
}
/** @hide */
@@ -625,6 +662,16 @@
/** @hide */
@TestApi
@NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+ public Builder setDeviceIcon(@Nullable Icon deviceIcon) {
+ mDeviceIcon = deviceIcon;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
public AssociationInfo build() {
if (mId <= 0) {
throw new IllegalArgumentException("Association ID should be greater than 0");
@@ -648,7 +695,8 @@
mPending,
mTimeApprovedMs,
mLastTimeConnectedMs,
- mSystemDataSyncFlags
+ mSystemDataSyncFlags,
+ mDeviceIcon
);
}
}
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 2e969f8..41a6791 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -23,12 +23,14 @@
import static java.util.Objects.requireNonNull;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.StringDef;
import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -234,6 +236,13 @@
private boolean mSkipPrompt;
/**
+ * The device icon displayed in selfManaged association dialog.
+ * @hide
+ */
+ @Nullable
+ private Icon mDeviceIcon;
+
+ /**
* Creates a new AssociationRequest.
*
* @param singleDevice
@@ -258,15 +267,16 @@
@Nullable @DeviceProfile String deviceProfile,
@Nullable CharSequence displayName,
boolean selfManaged,
- boolean forceConfirmation) {
+ boolean forceConfirmation,
+ @Nullable Icon deviceIcon) {
mSingleDevice = singleDevice;
mDeviceFilters = requireNonNull(deviceFilters);
mDeviceProfile = deviceProfile;
mDisplayName = displayName;
mSelfManaged = selfManaged;
mForceConfirmation = forceConfirmation;
-
mCreationTime = System.currentTimeMillis();
+ mDeviceIcon = deviceIcon;
}
/**
@@ -318,6 +328,19 @@
return mSingleDevice;
}
+ /**
+ * Get the device icon of the self-managed association request.
+ *
+ * @return the device icon, or {@code null} if no device icon has been set.
+ *
+ * @see Builder#setDeviceIcon(Icon)
+ */
+ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+ @Nullable
+ public Icon getDeviceIcon() {
+ return mDeviceIcon;
+ }
+
/** @hide */
public void setPackageName(@NonNull String packageName) {
mPackageName = packageName;
@@ -365,6 +388,7 @@
private CharSequence mDisplayName;
private boolean mSelfManaged = false;
private boolean mForceConfirmation = false;
+ private Icon mDeviceIcon = null;
public Builder() {}
@@ -450,6 +474,23 @@
return this;
}
+ /**
+ * Set the device icon for the self-managed device and this icon will be
+ * displayed in the self-managed association dialog.
+ *
+ * @throws IllegalArgumentException if the icon is not exactly 24dp by 24dp
+ * or if it is {@link Icon#TYPE_URI} or {@link Icon#TYPE_URI_ADAPTIVE_BITMAP}.
+ * @see #setSelfManaged(boolean)
+ */
+ @NonNull
+ @RequiresPermission(REQUEST_COMPANION_SELF_MANAGED)
+ @FlaggedApi(Flags.FLAG_ASSOCIATION_DEVICE_ICON)
+ public Builder setDeviceIcon(@NonNull Icon deviceIcon) {
+ checkNotUsed();
+ mDeviceIcon = requireNonNull(deviceIcon);
+ return this;
+ }
+
/** @inheritDoc */
@NonNull
@Override
@@ -460,7 +501,7 @@
+ "provide the display name of the device");
}
return new AssociationRequest(mSingleDevice, emptyIfNull(mDeviceFilters),
- mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation);
+ mDeviceProfile, mDisplayName, mSelfManaged, mForceConfirmation, mDeviceIcon);
}
}
@@ -561,7 +602,9 @@
&& Objects.equals(mDeviceProfilePrivilegesDescription,
that.mDeviceProfilePrivilegesDescription)
&& mCreationTime == that.mCreationTime
- && mSkipPrompt == that.mSkipPrompt;
+ && mSkipPrompt == that.mSkipPrompt
+ && (mDeviceIcon == null ? that.mDeviceIcon == null
+ : mDeviceIcon.sameAs(that.mDeviceIcon));
}
@Override
@@ -579,6 +622,8 @@
_hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
_hash = 31 * _hash + Long.hashCode(mCreationTime);
_hash = 31 * _hash + Boolean.hashCode(mSkipPrompt);
+ _hash = 31 * _hash + Objects.hashCode(mDeviceIcon);
+
return _hash;
}
@@ -606,6 +651,12 @@
dest.writeString8(mDeviceProfilePrivilegesDescription);
}
dest.writeLong(mCreationTime);
+ if (mDeviceIcon != null) {
+ dest.writeInt(1);
+ mDeviceIcon.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
}
@Override
@@ -650,6 +701,11 @@
this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
this.mCreationTime = creationTime;
this.mSkipPrompt = skipPrompt;
+ if (in.readInt() == 1) {
+ mDeviceIcon = Icon.CREATOR.createFromParcel(in);
+ } else {
+ mDeviceIcon = null;
+ }
}
@NonNull
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 1cdf3b1..dfad6de 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -20,6 +20,8 @@
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH;
+import static android.graphics.drawable.Icon.TYPE_URI;
+import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
import android.annotation.CallbackExecutor;
@@ -49,6 +51,11 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.graphics.drawable.VectorDrawable;
import android.net.MacAddress;
import android.os.Binder;
import android.os.Handler;
@@ -535,6 +542,13 @@
Objects.requireNonNull(executor, "Executor cannot be null");
Objects.requireNonNull(callback, "Callback cannot be null");
+ final Icon deviceIcon = request.getDeviceIcon();
+
+ if (deviceIcon != null && !isValidIcon(deviceIcon, mContext)) {
+ throw new IllegalArgumentException("The size of the device icon must be 24dp x 24dp to"
+ + "ensure proper display");
+ }
+
try {
mService.associate(request, new AssociationRequestCallbackProxy(executor, callback),
mContext.getOpPackageName(), mContext.getUserId());
@@ -2027,4 +2041,34 @@
}
}
}
+
+ private boolean isValidIcon(Icon icon, Context context) {
+ if (icon.getType() == TYPE_URI_ADAPTIVE_BITMAP || icon.getType() == TYPE_URI) {
+ throw new IllegalArgumentException("The URI based Icon is not supported.");
+ }
+ Drawable drawable = icon.loadDrawable(context);
+ float density = context.getResources().getDisplayMetrics().density;
+
+ if (drawable instanceof BitmapDrawable) {
+ Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+
+ float widthDp = bitmap.getWidth() / density;
+ float heightDp = bitmap.getHeight() / density;
+
+ if (widthDp != 24 || heightDp != 24) {
+ return false;
+ }
+ } else if (drawable instanceof VectorDrawable) {
+ VectorDrawable vectorDrawable = (VectorDrawable) drawable;
+ float widthDp = vectorDrawable.getIntrinsicWidth() / density;
+ float heightDp = vectorDrawable.getIntrinsicHeight() / density;
+
+ if (widthDp != 24 || heightDp != 24) {
+ return false;
+ }
+ } else {
+ throw new IllegalArgumentException("The format of the device icon is unsupported.");
+ }
+ return true;
+ }
}
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index 93d62cf..2539a12 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -55,3 +55,11 @@
description: "Enable association failure code API"
bug: "331459560"
}
+
+flag {
+ name: "association_device_icon"
+ is_exported: true
+ namespace: "companion"
+ description: "Enable set device icon API"
+ bug: "341057668"
+}
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index fa26837..6be7cc4 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -248,6 +248,50 @@
}
flag {
+ name: "cache_profile_parent_read_only"
+ namespace: "multiuser"
+ description: "Cache getProfileParent to avoid unnecessary binder calls"
+ bug: "350417399"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "cache_profile_ids_read_only"
+ namespace: "multiuser"
+ description: "Cache getProfileIds to avoid unnecessary binder calls"
+ bug: "350421409"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "cache_profile_type_read_only"
+ namespace: "multiuser"
+ description: "Cache getProfileType to avoid unnecessary binder calls"
+ bug: "350417403"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "cache_profiles_read_only"
+ namespace: "multiuser"
+ description: "Cache getProfiles to avoid unnecessary binder calls"
+ bug: "350419395"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+}
+
+flag {
name: "cache_quiet_mode_state"
namespace: "multiuser"
description: "Optimise quiet mode state retrieval"
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.java b/core/java/android/hardware/devicestate/DeviceStateInfo.java
index 28561ec..fd6f0b8 100644
--- a/core/java/android/hardware/devicestate/DeviceStateInfo.java
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.java
@@ -28,7 +28,6 @@
import java.util.Objects;
import java.util.concurrent.Executor;
-
/**
* Information about the state of the device.
*
@@ -63,11 +62,13 @@
* ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
* DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
*/
+ @NonNull
public final DeviceState baseState;
/**
* The state of the device.
*/
+ @NonNull
public final DeviceState currentState;
/**
@@ -78,8 +79,9 @@
*/
// Using the specific types to avoid virtual method calls in binder transactions
@SuppressWarnings("NonApiType")
- public DeviceStateInfo(@NonNull ArrayList<DeviceState> supportedStates, DeviceState baseState,
- DeviceState state) {
+ public DeviceStateInfo(@NonNull ArrayList<DeviceState> supportedStates,
+ @NonNull DeviceState baseState,
+ @NonNull DeviceState state) {
this.supportedStates = supportedStates;
this.baseState = baseState;
this.currentState = state;
@@ -97,7 +99,7 @@
public boolean equals(@Nullable Object other) {
if (this == other) return true;
if (other == null || (getClass() != other.getClass())) return false;
- DeviceStateInfo that = (DeviceStateInfo) other;
+ final DeviceStateInfo that = (DeviceStateInfo) other;
return baseState.equals(that.baseState)
&& currentState.equals(that.currentState)
&& Objects.equals(supportedStates, that.supportedStates);
@@ -126,8 +128,16 @@
return diff;
}
+ // Parcelable implementation
+
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Writes to Parcel. */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(supportedStates.size());
for (int i = 0; i < supportedStates.size(); i++) {
dest.writeTypedObject(supportedStates.get(i).getConfiguration(), flags);
@@ -137,28 +147,27 @@
dest.writeTypedObject(currentState.getConfiguration(), flags);
}
- @Override
- public int describeContents() {
- return 0;
+ /** Reads from Parcel. */
+ private DeviceStateInfo(@NonNull Parcel in) {
+ final int numberOfSupportedStates = in.readInt();
+ final ArrayList<DeviceState> supportedStates = new ArrayList<>(numberOfSupportedStates);
+ for (int i = 0; i < numberOfSupportedStates; i++) {
+ final DeviceState.Configuration configuration =
+ Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR));
+ supportedStates.add(i, new DeviceState(configuration));
+ }
+ this.supportedStates = supportedStates;
+
+ this.baseState = new DeviceState(
+ Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR)));
+ this.currentState = new DeviceState(
+ Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR)));
}
public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<>() {
@Override
- public DeviceStateInfo createFromParcel(Parcel source) {
- final int numberOfSupportedStates = source.readInt();
- final ArrayList<DeviceState> supportedStates = new ArrayList<>(numberOfSupportedStates);
- for (int i = 0; i < numberOfSupportedStates; i++) {
- DeviceState.Configuration configuration = source.readTypedObject(
- DeviceState.Configuration.CREATOR);
- supportedStates.add(i, new DeviceState(configuration));
- }
-
- final DeviceState baseState = new DeviceState(
- source.readTypedObject(DeviceState.Configuration.CREATOR));
- final DeviceState currentState = new DeviceState(
- source.readTypedObject(DeviceState.Configuration.CREATOR));
-
- return new DeviceStateInfo(supportedStates, baseState, currentState);
+ public DeviceStateInfo createFromParcel(@NonNull Parcel in) {
+ return new DeviceStateInfo(in);
}
@Override
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index 0c84019..1845827 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -46,6 +46,7 @@
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
public final class DeviceStateManagerGlobal {
+ @Nullable
private static DeviceStateManagerGlobal sInstance;
private static final String TAG = "DeviceStateManagerGlobal";
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
@@ -58,7 +59,7 @@
public static DeviceStateManagerGlobal getInstance() {
synchronized (DeviceStateManagerGlobal.class) {
if (sInstance == null) {
- IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
+ final IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
if (b != null) {
sInstance = new DeviceStateManagerGlobal(IDeviceStateManager
.Stub.asInterface(b));
@@ -94,6 +95,7 @@
*
* @see DeviceStateManager#getSupportedDeviceStates()
*/
+ @NonNull
public List<DeviceState> getSupportedDeviceStates() {
synchronized (mLock) {
final DeviceStateInfo currentInfo;
@@ -126,8 +128,8 @@
conditional = true)
public void requestState(@NonNull DeviceStateRequest request,
@Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) {
- DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback,
- executor);
+ final DeviceStateRequestWrapper requestWrapper =
+ new DeviceStateRequestWrapper(request, callback, executor);
synchronized (mLock) {
if (findRequestTokenLocked(request) != null) {
// This request has already been submitted.
@@ -136,7 +138,7 @@
// Add the request wrapper to the mRequests array before requesting the state as the
// callback could be triggered immediately if the mDeviceStateManager IBinder is in the
// same process as this instance.
- IBinder token = new Binder();
+ final IBinder token = new Binder();
mRequests.put(token, requestWrapper);
try {
@@ -176,8 +178,8 @@
@RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
public void requestBaseStateOverride(@NonNull DeviceStateRequest request,
@Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) {
- DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback,
- executor);
+ final DeviceStateRequestWrapper requestWrapper =
+ new DeviceStateRequestWrapper(request, callback, executor);
synchronized (mLock) {
if (findRequestTokenLocked(request) != null) {
// This request has already been submitted.
@@ -186,7 +188,7 @@
// Add the request wrapper to the mRequests array before requesting the state as the
// callback could be triggered immediately if the mDeviceStateManager IBinder is in the
// same process as this instance.
- IBinder token = new Binder();
+ final IBinder token = new Binder();
mRequests.put(token, requestWrapper);
try {
@@ -225,7 +227,7 @@
public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
@NonNull Executor executor) {
synchronized (mLock) {
- int index = findCallbackLocked(callback);
+ final int index = findCallbackLocked(callback);
if (index != -1) {
// This callback is already registered.
return;
@@ -233,7 +235,8 @@
// Add the callback wrapper to the mCallbacks array after registering the callback as
// the callback could be triggered immediately if the mDeviceStateManager IBinder is in
// the same process as this instance.
- DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor);
+ final DeviceStateCallbackWrapper wrapper =
+ new DeviceStateCallbackWrapper(callback, executor);
mCallbacks.add(wrapper);
if (mLastReceivedInfo != null) {
@@ -253,7 +256,7 @@
@VisibleForTesting(visibility = Visibility.PACKAGE)
public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
synchronized (mLock) {
- int indexToRemove = findCallbackLocked(callback);
+ final int indexToRemove = findCallbackLocked(callback);
if (indexToRemove != -1) {
mCallbacks.remove(indexToRemove);
}
@@ -277,14 +280,16 @@
}
private void registerCallbackIfNeededLocked() {
- if (mCallback == null) {
- mCallback = new DeviceStateManagerCallback();
- try {
- mDeviceStateManager.registerCallback(mCallback);
- } catch (RemoteException ex) {
- mCallback = null;
- throw ex.rethrowFromSystemServer();
- }
+ if (mCallback != null) {
+ return;
+ }
+
+ mCallback = new DeviceStateManagerCallback();
+ try {
+ mDeviceStateManager.registerCallback(mCallback);
+ } catch (RemoteException ex) {
+ mCallback = null;
+ throw ex.rethrowFromSystemServer();
}
}
@@ -298,6 +303,7 @@
}
@Nullable
+ @GuardedBy("mLock")
private IBinder findRequestTokenLocked(@NonNull DeviceStateRequest request) {
for (int i = 0; i < mRequests.size(); i++) {
if (mRequests.valueAt(i).mRequest.equals(request)) {
@@ -309,8 +315,8 @@
/** Handles a call from the server that the device state info has changed. */
private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
- ArrayList<DeviceStateCallbackWrapper> callbacks;
- DeviceStateInfo oldInfo;
+ final ArrayList<DeviceStateCallbackWrapper> callbacks;
+ final DeviceStateInfo oldInfo;
synchronized (mLock) {
oldInfo = mLastReceivedInfo;
mLastReceivedInfo = info;
@@ -335,8 +341,8 @@
* Handles a call from the server that a request for the supplied {@code token} has become
* active.
*/
- private void handleRequestActive(IBinder token) {
- DeviceStateRequestWrapper request;
+ private void handleRequestActive(@NonNull IBinder token) {
+ final DeviceStateRequestWrapper request;
synchronized (mLock) {
request = mRequests.get(token);
}
@@ -349,8 +355,8 @@
* Handles a call from the server that a request for the supplied {@code token} has become
* canceled.
*/
- private void handleRequestCanceled(IBinder token) {
- DeviceStateRequestWrapper request;
+ private void handleRequestCanceled(@NonNull IBinder token) {
+ final DeviceStateRequestWrapper request;
synchronized (mLock) {
request = mRequests.remove(token);
}
@@ -361,17 +367,17 @@
private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
@Override
- public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+ public void onDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
handleDeviceStateInfoChanged(info);
}
@Override
- public void onRequestActive(IBinder token) {
+ public void onRequestActive(@NonNull IBinder token) {
handleRequestActive(token);
}
@Override
- public void onRequestCanceled(IBinder token) {
+ public void onRequestCanceled(@NonNull IBinder token) {
handleRequestCanceled(token);
}
}
@@ -388,7 +394,8 @@
mExecutor = executor;
}
- void notifySupportedDeviceStatesChanged(List<DeviceState> newSupportedDeviceStates) {
+ void notifySupportedDeviceStatesChanged(
+ @NonNull List<DeviceState> newSupportedDeviceStates) {
mExecutor.execute(() ->
mDeviceStateCallback.onSupportedStatesChanged(newSupportedDeviceStates));
}
@@ -398,7 +405,7 @@
() -> mDeviceStateCallback.onDeviceStateChanged(newDeviceState));
}
- private void execute(String traceName, Runnable r) {
+ private void execute(@NonNull String traceName, @NonNull Runnable r) {
mExecutor.execute(() -> {
if (DEBUG) {
Trace.beginSection(
@@ -416,6 +423,7 @@
}
private static final class DeviceStateRequestWrapper {
+ @NonNull
private final DeviceStateRequest mRequest;
@Nullable
private final DeviceStateRequest.Callback mCallback;
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index dfc591b..8ef62e3 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -62,7 +62,7 @@
* sleep (CPU off, display dark, device waiting for external input),
* but is not affected by clock scaling, idle, or other power saving
* mechanisms. This is the basis for most interval timing
- * such as {@link Thread#sleep(long) Thread.sleep(millls)},
+ * such as {@link Thread#sleep(long) Thread.sleep(millis)},
* {@link Object#wait(long) Object.wait(millis)}, and
* {@link System#nanoTime System.nanoTime()}. This clock is guaranteed
* to be monotonic, and is suitable for interval timing when the
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index bca5bcc..feeb339 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -206,17 +206,6 @@
}
flag {
- name: "apex_signature_permission_allowlist_enabled"
- is_fixed_read_only: true
- namespace: "permissions"
- description: "Enable reading signature permission allowlist from APEXes"
- bug: "308573169"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "check_op_validate_package"
namespace: "permissions"
description: "Validate package/uid match in checkOp similar to noteOp"
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 98d58d0..5ecf361 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3209,7 +3209,11 @@
return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_NOT_SET, null);
}
- private static boolean isCloudOrSimAccount(@DefaultAccountState int state) {
+ /**
+ *
+ * @hide
+ */
+ public static boolean isCloudOrSimAccount(@DefaultAccountState int state) {
return state == DEFAULT_ACCOUNT_STATE_CLOUD
|| state == DEFAULT_ACCOUNT_STATE_SIM;
}
@@ -3287,23 +3291,20 @@
Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, null);
- int defaultContactsAccountState = response.getInt(KEY_DEFAULT_ACCOUNT_STATE, -1);
- if (defaultContactsAccountState
- == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
+ int defaultAccountState = response.getInt(KEY_DEFAULT_ACCOUNT_STATE, -1);
+ if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountState)) {
String accountName = response.getString(Settings.ACCOUNT_NAME);
String accountType = response.getString(Settings.ACCOUNT_TYPE);
if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
throw new IllegalStateException(
"account name and type cannot be null or empty");
}
- return new DefaultAccountAndState(
- DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD,
+ return new DefaultAccountAndState(defaultAccountState,
new Account(accountName, accountType));
- } else if (defaultContactsAccountState
- == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL
- || defaultContactsAccountState
+ } else if (defaultAccountState == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL
+ || defaultAccountState
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET) {
- return new DefaultAccountAndState(defaultContactsAccountState, /*cloudAccount=*/
+ return new DefaultAccountAndState(defaultAccountState, /*account=*/
null);
} else {
throw new IllegalStateException("Invalid default account state");
@@ -3348,12 +3349,11 @@
Bundle extras = new Bundle();
extras.putInt(KEY_DEFAULT_ACCOUNT_STATE, defaultAccountAndState.getState());
- if (defaultAccountAndState.getState()
- == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
- Account cloudAccount = defaultAccountAndState.getAccount();
- assert cloudAccount != null;
- extras.putString(Settings.ACCOUNT_NAME, cloudAccount.name);
- extras.putString(Settings.ACCOUNT_TYPE, cloudAccount.type);
+ if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountAndState.getState())) {
+ Account account = defaultAccountAndState.getAccount();
+ assert account != null;
+ extras.putString(Settings.ACCOUNT_NAME, account.name);
+ extras.putString(Settings.ACCOUNT_TYPE, account.type);
}
nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, extras);
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index ec5b488..09b2201 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -188,3 +188,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "tts_span_duration"
+ namespace: "text"
+ description: "Feature flag for adding a TYPE_DURATION to TtsSpan"
+ bug: "337103893"
+}
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index f9a1a0d..b7b8f0b1 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -16,6 +16,10 @@
package android.text.style;
+import static com.android.text.flags.Flags.FLAG_TTS_SPAN_DURATION;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.text.ParcelableSpan;
@@ -112,6 +116,16 @@
public static final String TYPE_TIME = "android.type.time";
/**
+ * The text associated with this span is a duration, consisting of a number of
+ * hours, minutes, and seconds specified with {@link #ARG_HOURS},
+ * {@link #ARG_MINUTES}, and {@link #ARG_SECONDS}. This is different from {@link #TYPE_TIME}.
+ * This should be used to convey an interval of time, while {@link #TYPE_TIME} should be used to
+ * convey a particular moment in time, such as a clock time.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public static final String TYPE_DURATION = "android.type.duration";
+
+ /**
* The text associated with this span is a date. At least one of the
* arguments {@link #ARG_MONTH} and {@link #ARG_YEAR} has to be provided.
* The argument {@link #ARG_DAY} is optional if {@link #ARG_MONTH} is set.
@@ -302,13 +316,21 @@
public static final String ARG_HOURS = "android.arg.hours";
/**
- * Argument used to specify the minutes of a time. The hours should be
+ * Argument used to specify the minutes of a time. The minutes should be
* provided as an integer in the range from 0 up to and including 59.
* Can be used with {@link #TYPE_TIME}.
*/
public static final String ARG_MINUTES = "android.arg.minutes";
/**
+ * Argument used to specify the seconds of a time or duration. The seconds should be
+ * provided as an integer in the range from 0 up to and including 59.
+ * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public static final String ARG_SECONDS = "android.arg.seconds";
+
+ /**
* Argument used to specify the weekday of a date. The value should be
* provided as an integer and can be any of {@link #WEEKDAY_SUNDAY},
* {@link #WEEKDAY_MONDAY}, {@link #WEEKDAY_TUESDAY},
@@ -1132,9 +1154,70 @@
public TimeBuilder setMinutes(int minutes) {
return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
}
+
+ /**
+ * Sets the {@link #ARG_SECONDS} argument.
+ * @param seconds The value to be set for seconds.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public TimeBuilder setSeconds(int seconds) {
+ return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
+ }
}
/**
+ * A builder for TtsSpans of type {@link #TYPE_DURATION}.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public static class DurationBuilder
+ extends SemioticClassBuilder<DurationBuilder> {
+
+ /**
+ * Creates a builder for a TtsSpan of type {@link #TYPE_DURATION}.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ public DurationBuilder() {
+ super(TtsSpan.TYPE_DURATION);
+ }
+
+ /**
+ * Sets the {@link #ARG_HOURS} argument.
+ * @param hours The value to be set for hours.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public DurationBuilder setHours(int hours) {
+ return setIntArgument(TtsSpan.ARG_HOURS, hours);
+ }
+
+ /**
+ * Sets the {@link #ARG_MINUTES} argument.
+ * @param minutes The value to be set for minutes.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public DurationBuilder setMinutes(int minutes) {
+ return setIntArgument(TtsSpan.ARG_MINUTES, minutes);
+ }
+
+ /**
+ * Sets the {@link #ARG_SECONDS} argument.
+ * @param seconds The value to be set for seconds.
+ * @return This instance.
+ */
+ @FlaggedApi(FLAG_TTS_SPAN_DURATION)
+ @NonNull
+ public DurationBuilder setSeconds(int seconds) {
+ return setIntArgument(TtsSpan.ARG_SECONDS, seconds);
+ }
+ }
+
+
+ /**
* A builder for TtsSpans of type {@link #TYPE_DATE}.
*/
public static class DateBuilder
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 5c41516..67050e0 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -38,7 +38,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0ca442d..5afc7b2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -125,7 +125,7 @@
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index b9e9750..69cbb9b 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -11,6 +11,13 @@
}
flag {
+ name: "a11y_is_required_api"
+ namespace: "accessibility"
+ description: "Adds an API to indicate whether a form field (or similar element) is required."
+ bug: "362784403"
+}
+
+flag {
name: "a11y_overlay_callbacks"
is_exported: true
namespace: "accessibility"
@@ -210,3 +217,13 @@
description: "Feature flag for declaring system pinch zoom opt-out apis"
bug: "315089687"
}
+
+flag {
+ name: "warning_use_default_dialog_type"
+ namespace: "accessibility"
+ description: "Uses the default type for the A11yService warning dialog, instead of SYSTEM_ALERT_DIALOG"
+ bug: "336719951"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index f570a9a..5115b13 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -97,4 +97,15 @@
description: "Disable Draw Wakelock starting U."
bug: "331698645"
is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+ name: "calculate_bounds_in_parent_from_bounds_in_screen"
+ namespace: "accessibility"
+ description: "Calculate bounds in parent of each node in ViewStructure from its bounds set relative to screen and its parent's"
+ bug: "366131857"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 806a593..0a83bdc 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -860,7 +860,7 @@
* <p>e.g.<pre><code>startActivity(createStylusHandwritingSettingsActivityIntent());</code>
* </pre></p>
*
- * @attr ref R.styleable#InputMethod_stylusHandwritingSettingsActivity
+ * @attr ref android.R.styleable#InputMethod_stylusHandwritingSettingsActivity
* @see #getSettingsActivity()
* @see #supportsStylusHandwriting()
*/
@@ -888,8 +888,8 @@
* the IME language settings activity.</p>
* <p>e.g.<pre><code>startActivity(createImeLanguageSettingsActivityIntent());</code></pre></p>
*
- * @attr ref R.styleable#InputMethod_languageSettingsActivity
- * @attr ref R.styleable#InputMethod_settingsActivity
+ * @attr ref android.R.styleable#InputMethod_languageSettingsActivity
+ * @attr ref android.R.styleable#InputMethod_settingsActivity
*/
@FlaggedApi(android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API)
@Nullable
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 510a92d..3f611c7 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3636,7 +3636,7 @@
* Returns the drawable that will be drawn between each item in the list.
*
* @return the current drawable drawn between list elements
- * @attr ref R.styleable#ListView_divider
+ * @attr ref android.R.styleable#ListView_divider
*/
@InspectableProperty
@Nullable
@@ -3651,7 +3651,7 @@
* height, you should also call {@link #setDividerHeight(int)}.
*
* @param divider the drawable to use
- * @attr ref R.styleable#ListView_divider
+ * @attr ref android.R.styleable#ListView_divider
*/
public void setDivider(@Nullable Drawable divider) {
if (divider != null) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 06820cd..d7b5211 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -46,6 +46,7 @@
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.appwidget.AppWidgetHostView;
+import android.appwidget.flags.Flags;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -4119,6 +4120,71 @@
public void visitUris(@NonNull Consumer<Uri> visitor) {
mNestedViews.visitUris(visitor);
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ if (!Flags.remoteViewsProto()) return;
+ final long token = out.start(RemoteViewsProto.Action.VIEW_GROUP_ADD_ACTION);
+ out.write(RemoteViewsProto.ViewGroupAddAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.ViewGroupAddAction.INDEX, mIndex);
+ out.write(RemoteViewsProto.ViewGroupAddAction.STABLE_ID, mStableId);
+ long rvToken = out.start(RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS);
+ mNestedViews.writePreviewToProto(context, out);
+ out.end(rvToken);
+ out.end(token);
+ }
+ }
+
+ private PendingResources<Action> createViewGroupActionAddFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.VIEW_GROUP_ADD_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.ViewGroupAddAction.VIEW_ID:
+ values.put(RemoteViewsProto.ViewGroupAddAction.VIEW_ID,
+ in.readString(RemoteViewsProto.ViewGroupAddAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS:
+ final long nvToken = in.start(RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS);
+ values.put(RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS,
+ createFromProto(in));
+ in.end(nvToken);
+ break;
+ case (int) RemoteViewsProto.ViewGroupAddAction.INDEX:
+ values.put(RemoteViewsProto.ViewGroupAddAction.INDEX,
+ in.readInt(RemoteViewsProto.ViewGroupAddAction.INDEX));
+ break;
+ case (int) RemoteViewsProto.ViewGroupAddAction.STABLE_ID:
+ values.put(RemoteViewsProto.ViewGroupAddAction.STABLE_ID,
+ in.readInt(RemoteViewsProto.ViewGroupAddAction.STABLE_ID));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.ViewGroupAddAction.VIEW_ID,
+ RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.ViewGroupAddAction.VIEW_ID);
+ return new ViewGroupActionAdd(viewId, ((PendingResources<RemoteViews>) values.get(
+ RemoteViewsProto.ViewGroupAddAction.NESTED_VIEWS)).create(context, resources,
+ rootData, depth),
+ (int) values.get(RemoteViewsProto.ViewGroupAddAction.INDEX, 0),
+ (int) values.get(RemoteViewsProto.ViewGroupAddAction.STABLE_ID, 0));
+ };
}
/**
@@ -4241,6 +4307,60 @@
public int mergeBehavior() {
return MERGE_APPEND;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.VIEW_GROUP_REMOVE_ACTION);
+ out.write(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ if (mViewIdToKeep != REMOVE_ALL_VIEWS_ID) {
+ out.write(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP,
+ appResources.getResourceName(mViewIdToKeep));
+ }
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.VIEW_GROUP_REMOVE_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID:
+ values.put(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID,
+ in.readString(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP:
+ values.put(RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP,
+ in.readString(
+ RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID);
+ int viewIdToKeep = (values.indexOfKey(
+ RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP) >= 0)
+ ? getAsIdentifier(resources, values,
+ RemoteViewsProto.ViewGroupRemoveAction.VIEW_ID_TO_KEEP)
+ : REMOVE_ALL_VIEWS_ID;
+ return new ViewGroupActionRemove(viewId, viewIdToKeep);
+ };
+ }
}
/**
@@ -4497,6 +4617,200 @@
visitIconUri(mI4, visitor);
}
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context,
+ Resources appResources) { // rebase
+ final long token = out.start(RemoteViewsProto.Action.TEXT_VIEW_DRAWABLE_ACTION);
+ out.write(RemoteViewsProto.TextViewDrawableAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE, mIsRelative);
+ if (mUseIcons) {
+ long iconsToken = out.start(RemoteViewsProto.TextViewDrawableAction.ICONS);
+ if (mI1 != null) {
+ writeIconToProto(out, appResources, mI1,
+ RemoteViewsProto.TextViewDrawableAction.Icons.ONE);
+ }
+ if (mI2 != null) {
+ writeIconToProto(out, appResources, mI2,
+ RemoteViewsProto.TextViewDrawableAction.Icons.TWO);
+ }
+ if (mI3 != null) {
+ writeIconToProto(out, appResources, mI3,
+ RemoteViewsProto.TextViewDrawableAction.Icons.THREE);
+ }
+ if (mI4 != null) {
+ writeIconToProto(out, appResources, mI4,
+ RemoteViewsProto.TextViewDrawableAction.Icons.FOUR);
+ }
+ out.end(iconsToken);
+ } else {
+ long resourcesToken = out.start(RemoteViewsProto.TextViewDrawableAction.RESOURCES);
+ if (mD1 != 0) {
+ out.write(RemoteViewsProto.TextViewDrawableAction.Resources.ONE,
+ appResources.getResourceName(mD1));
+ }
+ if (mD2 != 0) {
+ out.write(RemoteViewsProto.TextViewDrawableAction.Resources.TWO,
+ appResources.getResourceName(mD2));
+ }
+ if (mD3 != 0) {
+ out.write(RemoteViewsProto.TextViewDrawableAction.Resources.THREE,
+ appResources.getResourceName(mD3));
+ }
+ if (mD4 != 0) {
+ out.write(RemoteViewsProto.TextViewDrawableAction.Resources.FOUR,
+ appResources.getResourceName(mD4));
+ }
+ out.end(resourcesToken);
+ }
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ values.put(RemoteViewsProto.TextViewDrawableAction.ICONS,
+ new SparseArray<PendingResources<Icon>>());
+ values.put(RemoteViewsProto.TextViewDrawableAction.RESOURCES,
+ new SparseArray<String>());
+ final long token = in.start(RemoteViewsProto.Action.TEXT_VIEW_DRAWABLE_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.TextViewDrawableAction.VIEW_ID:
+ values.put(RemoteViewsProto.TextViewDrawableAction.VIEW_ID,
+ in.readString(RemoteViewsProto.TextViewDrawableAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE:
+ values.put(RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE,
+ in.readBoolean(
+ RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.RESOURCES:
+ final long resourcesToken = in.start(
+ RemoteViewsProto.TextViewDrawableAction.RESOURCES);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.TextViewDrawableAction.Resources.ONE:
+ ((SparseArray<String>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+ 1, in.readString(
+ RemoteViewsProto
+ .TextViewDrawableAction.Resources.ONE));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.Resources.TWO:
+ ((SparseArray<String>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+ 2, in.readString(
+ RemoteViewsProto
+ .TextViewDrawableAction.Resources.TWO));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.Resources.THREE:
+ ((SparseArray<String>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+ 3, in.readString(
+ RemoteViewsProto
+ .TextViewDrawableAction
+ .Resources.THREE));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.Resources.FOUR:
+ ((SparseArray<String>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.RESOURCES)).put(
+ 4, in.readString(
+ RemoteViewsProto
+ .TextViewDrawableAction
+ .Resources.FOUR));
+ break;
+ default:
+ Log.w(LOG_TAG,
+ "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(resourcesToken);
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.ICONS:
+ final long iconsToken = in.start(
+ RemoteViewsProto.TextViewDrawableAction.ICONS);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.TextViewDrawableAction.Icons.ONE:
+ ((SparseArray<PendingResources<Icon>>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.ICONS)).put(1,
+ createIconFromProto(in,
+ RemoteViewsProto
+ .TextViewDrawableAction.Icons.ONE));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.Icons.TWO:
+ ((SparseArray<PendingResources<Icon>>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.ICONS)).put(2,
+ createIconFromProto(in,
+ RemoteViewsProto
+ .TextViewDrawableAction.Icons.TWO));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.Icons.THREE:
+ ((SparseArray<PendingResources<Icon>>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.ICONS)).put(3,
+ createIconFromProto(in,
+ RemoteViewsProto
+ .TextViewDrawableAction.Icons.THREE));
+ break;
+ case (int) RemoteViewsProto.TextViewDrawableAction.Icons.FOUR:
+ ((SparseArray<PendingResources<Icon>>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.ICONS)).put(4,
+ createIconFromProto(in,
+ RemoteViewsProto
+ .TextViewDrawableAction.Icons.FOUR));
+ break;
+ default:
+ Log.w(LOG_TAG,
+ "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(iconsToken);
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.TextViewDrawableAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.TextViewDrawableAction.VIEW_ID);
+ SparseArray<PendingResources<Icon>> icons =
+ (SparseArray<PendingResources<Icon>>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.ICONS);
+ SparseArray<String> resArray = (SparseArray<String>) values.get(
+ RemoteViewsProto.TextViewDrawableAction.RESOURCES);
+ boolean isRelative = (boolean) values.get(
+ RemoteViewsProto.TextViewDrawableAction.IS_RELATIVE, false);
+ if (icons.size() > 0) {
+ return new TextViewDrawableAction(viewId, isRelative,
+ icons.get(1).create(context, resources, rootData, depth),
+ icons.get(2).create(context, resources, rootData, depth),
+ icons.get(3).create(context, resources, rootData, depth),
+ icons.get(4).create(context, resources, rootData, depth));
+ } else {
+ int first = resArray.contains(1) ? getAsIdentifier(resources, resArray, 1) : 0;
+ int second = resArray.contains(2) ? getAsIdentifier(resources, resArray, 2) : 0;
+ int third = resArray.contains(3) ? getAsIdentifier(resources, resArray, 3) : 0;
+ int fourth = resArray.contains(4) ? getAsIdentifier(resources, resArray, 4) : 0;
+ return new TextViewDrawableAction(viewId, isRelative, first, second, third,
+ fourth);
+ }
+ };
+ }
}
/**
@@ -4535,6 +4849,58 @@
public int getActionTag() {
return TEXT_VIEW_SIZE_ACTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.TEXT_VIEW_SIZE_ACTION);
+ out.write(RemoteViewsProto.TextViewSizeAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.TextViewSizeAction.UNITS, mUnits);
+ out.write(RemoteViewsProto.TextViewSizeAction.SIZE, mSize);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.TEXT_VIEW_SIZE_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.TextViewSizeAction.VIEW_ID:
+ values.put(RemoteViewsProto.TextViewSizeAction.VIEW_ID,
+ in.readString(RemoteViewsProto.TextViewSizeAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.TextViewSizeAction.UNITS:
+ values.put(RemoteViewsProto.TextViewSizeAction.UNITS,
+ in.readInt(RemoteViewsProto.TextViewSizeAction.UNITS));
+ break;
+ case (int) RemoteViewsProto.TextViewSizeAction.SIZE:
+ values.put(RemoteViewsProto.TextViewSizeAction.SIZE,
+ in.readFloat(RemoteViewsProto.TextViewSizeAction.SIZE));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.TextViewSizeAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.TextViewSizeAction.VIEW_ID);
+ return new TextViewSizeAction(viewId,
+ (int) values.get(RemoteViewsProto.TextViewSizeAction.UNITS, 0),
+ (float) values.get(RemoteViewsProto.TextViewSizeAction.SIZE, 0));
+ };
+ }
}
/**
@@ -4579,6 +4945,70 @@
public int getActionTag() {
return VIEW_PADDING_ACTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.VIEW_PADDING_ACTION);
+ out.write(RemoteViewsProto.ViewPaddingAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.ViewPaddingAction.LEFT, mLeft);
+ out.write(RemoteViewsProto.ViewPaddingAction.RIGHT, mRight);
+ out.write(RemoteViewsProto.ViewPaddingAction.TOP, mTop);
+ out.write(RemoteViewsProto.ViewPaddingAction.BOTTOM, mBottom);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.VIEW_PADDING_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.ViewPaddingAction.VIEW_ID:
+ values.put(RemoteViewsProto.ViewPaddingAction.VIEW_ID,
+ in.readString(RemoteViewsProto.ViewPaddingAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.ViewPaddingAction.LEFT:
+ values.put(RemoteViewsProto.ViewPaddingAction.LEFT,
+ in.readInt(RemoteViewsProto.ViewPaddingAction.LEFT));
+ break;
+ case (int) RemoteViewsProto.ViewPaddingAction.RIGHT:
+ values.put(RemoteViewsProto.ViewPaddingAction.RIGHT,
+ in.readInt(RemoteViewsProto.ViewPaddingAction.RIGHT));
+ break;
+ case (int) RemoteViewsProto.ViewPaddingAction.TOP:
+ values.put(RemoteViewsProto.ViewPaddingAction.TOP,
+ in.readInt(RemoteViewsProto.ViewPaddingAction.TOP));
+ break;
+ case (int) RemoteViewsProto.ViewPaddingAction.BOTTOM:
+ values.put(RemoteViewsProto.ViewPaddingAction.BOTTOM,
+ in.readInt(RemoteViewsProto.ViewPaddingAction.BOTTOM));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.ViewPaddingAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.ViewPaddingAction.VIEW_ID);
+ return new ViewPaddingAction(viewId,
+ (int) values.get(RemoteViewsProto.ViewPaddingAction.LEFT, 0),
+ (int) values.get(RemoteViewsProto.ViewPaddingAction.TOP, 0),
+ (int) values.get(RemoteViewsProto.ViewPaddingAction.RIGHT, 0),
+ (int) values.get(RemoteViewsProto.ViewPaddingAction.BOTTOM, 0));
+ };
+ }
}
/**
@@ -5241,6 +5671,69 @@
public int getActionTag() {
return SET_VIEW_OUTLINE_RADIUS_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(
+ RemoteViewsProto.Action.SET_VIEW_OUTLINE_PREFERRED_RADIUS_ACTION);
+ out.write(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE, mValueType);
+ out.write(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE, mValue);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(
+ RemoteViewsProto.Action.SET_VIEW_OUTLINE_PREFERRED_RADIUS_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto
+ .SetViewOutlinePreferredRadiusAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE:
+ values.put(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE,
+ in.readInt(
+ RemoteViewsProto
+ .SetViewOutlinePreferredRadiusAction.VALUE_TYPE));
+ break;
+ case (int) RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE:
+ values.put(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE,
+ in.readInt(
+ RemoteViewsProto
+ .SetViewOutlinePreferredRadiusAction.VALUE));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID,
+ RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VIEW_ID);
+ return new SetViewOutlinePreferredRadiusAction(viewId,
+ (int) values.get(RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE,
+ 0), (int) values.get(
+ RemoteViewsProto.SetViewOutlinePreferredRadiusAction.VALUE_TYPE));
+ };
+ }
}
/**
@@ -5324,6 +5817,46 @@
public int getActionTag() {
return SET_DRAW_INSTRUCTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return drawDataParcel();
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ if (!drawDataParcel()) return;
+ final long token = out.start(RemoteViewsProto.Action.SET_DRAW_INSTRUCTION_ACTION);
+ if (mInstructions != null) {
+ for (byte[] bytes : mInstructions.mInstructions) {
+ out.write(RemoteViewsProto.SetDrawInstructionAction.INSTRUCTIONS, bytes);
+ }
+ }
+ out.end(token);
+ }
+ }
+
+ @FlaggedApi(FLAG_DRAW_DATA_PARCEL)
+ private PendingResources<Action> createSetDrawInstructionActionFromProto(ProtoInputStream in)
+ throws Exception {
+ List<byte[]> instructions = new ArrayList<byte[]>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_DRAW_INSTRUCTION_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetDrawInstructionAction.INSTRUCTIONS:
+ instructions.add(
+ in.readBytes(RemoteViewsProto.SetDrawInstructionAction.INSTRUCTIONS));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ return (context, resources, rootData, depth) -> new SetDrawInstructionAction(
+ new DrawInstructions.Builder(instructions).build());
}
/**
@@ -9604,12 +10137,20 @@
}
if (ref.mMode == MODE_NORMAL) {
rv.setIdealSize(ref.mIdealSize);
+ boolean hasDrawInstructionAction = false;
for (PendingResources<Action> pendingAction : ref.mActions) {
Action action = pendingAction.create(appContext, appResources, rootData, depth);
if (action != null) {
+ if (action instanceof SetDrawInstructionAction) {
+ hasDrawInstructionAction = true;
+ }
rv.addAction(action);
}
}
+ if (rv.mHasDrawInstructions && !hasDrawInstructionAction) {
+ throw new InvalidProtoException(
+ "RemoteViews proto is missing DrawInstructions");
+ }
return rv;
} else if (ref.mMode == MODE_HAS_SIZED_REMOTEVIEWS) {
List<RemoteViews> sizedViews = new ArrayList<>();
@@ -9685,6 +10226,23 @@
return rv.createSetRemoteCollectionItemListAdapterActionFromProto(in);
case (int) RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION:
return SetRippleDrawableColor.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_VIEW_OUTLINE_PREFERRED_RADIUS_ACTION:
+ return SetViewOutlinePreferredRadiusAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.TEXT_VIEW_DRAWABLE_ACTION:
+ return TextViewDrawableAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.TEXT_VIEW_SIZE_ACTION:
+ return TextViewSizeAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.VIEW_GROUP_ADD_ACTION:
+ return rv.createViewGroupActionAddFromProto(in);
+ case (int) RemoteViewsProto.Action.VIEW_GROUP_REMOVE_ACTION:
+ return ViewGroupActionRemove.createFromProto(in);
+ case (int) RemoteViewsProto.Action.VIEW_PADDING_ACTION:
+ return ViewPaddingAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_DRAW_INSTRUCTION_ACTION:
+ if (!drawDataParcel()) {
+ return null;
+ }
+ return rv.createSetDrawInstructionActionFromProto(in);
default:
throw new RuntimeException("Unhandled field while reading Action proto!\n"
+ ProtoUtils.currentFieldToString(in));
diff --git a/core/java/android/window/flags/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
similarity index 99%
rename from core/java/android/window/flags/DesktopModeFlags.java
rename to core/java/android/window/DesktopModeFlags.java
index 47af50da..6fb82af 100644
--- a/core/java/android/window/flags/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.window.flags;
+package android.window;
import android.annotation.Nullable;
import android.app.ActivityThread;
diff --git a/core/java/android/window/KeyguardState.aidl b/core/java/android/window/KeyguardState.aidl
new file mode 100644
index 0000000..9612d95
--- /dev/null
+++ b/core/java/android/window/KeyguardState.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+/**
+ * @hide
+ */
+parcelable KeyguardState;
diff --git a/core/java/android/window/KeyguardState.java b/core/java/android/window/KeyguardState.java
new file mode 100644
index 0000000..6584d30
--- /dev/null
+++ b/core/java/android/window/KeyguardState.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data object of params for Keyguard related {@link WindowContainerTransaction} operation.
+ *
+ * @hide
+ */
+public final class KeyguardState implements Parcelable {
+
+ private final int mDisplayId;
+
+ private final boolean mKeyguardShowing;
+
+ private final boolean mAodShowing;
+
+
+ private KeyguardState(int displayId, boolean keyguardShowing, boolean aodShowing) {
+ mDisplayId = displayId;
+ mKeyguardShowing = keyguardShowing;
+ mAodShowing = aodShowing;
+ }
+
+ private KeyguardState(Parcel in) {
+ mDisplayId = in.readInt();
+ mKeyguardShowing = in.readBoolean();
+ mAodShowing = in.readBoolean();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mDisplayId);
+ dest.writeBoolean(mKeyguardShowing);
+ dest.writeBoolean(mAodShowing);
+ }
+
+ @NonNull
+ public static final Creator<KeyguardState> CREATOR =
+ new Creator<KeyguardState>() {
+ @Override
+ public KeyguardState createFromParcel(Parcel in) {
+ return new KeyguardState(in);
+ }
+
+ @Override
+ public KeyguardState[] newArray(int size) {
+ return new KeyguardState[size];
+ }
+ };
+
+ /**
+ * Gets the display id of this {@link KeyguardState}.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /** Returns the keyguard showing value. */
+ public boolean getKeyguardShowing() {
+ return mKeyguardShowing;
+ }
+
+ /** Returns the aod showing value. */
+ public boolean getAodShowing() {
+ return mAodShowing;
+ }
+
+ @Override
+ public String toString() {
+ return "KeyguardState{ displayId=" + mDisplayId
+ + ", keyguardShowing=" + mKeyguardShowing
+ + ", aodShowing=" + mAodShowing
+ + '}';
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDisplayId, mKeyguardShowing, mAodShowing);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof KeyguardState other)) {
+ return false;
+ }
+ return mDisplayId == other.mDisplayId
+ && mKeyguardShowing == other.mKeyguardShowing
+ && mAodShowing == other.mAodShowing;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Builder to construct the {@link KeyguardState}. */
+ public static final class Builder {
+
+ private final int mDisplayId;
+
+ private boolean mKeyguardShowing;
+
+ private boolean mAodShowing;
+
+ /**
+ * @param displayId the display of this {@link KeyguardState}.
+ */
+ public Builder(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ /**
+ * Sets the boolean value for this operation.
+ */
+ @NonNull
+ public Builder setKeyguardShowing(boolean keyguardShowing) {
+ mKeyguardShowing = keyguardShowing;
+ return this;
+ }
+
+ /**
+ * Sets the boolean value for this operation.
+ */
+ @NonNull
+ public Builder setAodShowing(boolean aodShowing) {
+ mAodShowing = aodShowing;
+ return this;
+ }
+
+ /**
+ * Constructs the {@link KeyguardState}.
+ */
+ @NonNull
+ public KeyguardState build() {
+ return new KeyguardState(mDisplayId, mKeyguardShowing, mAodShowing);
+ }
+ }
+}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 0dc9263..8e495ec 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -869,6 +869,24 @@
}
/**
+ * Adds a {@link KeyguardState} to apply to the given displays.
+ *
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction addKeyguardState(
+ @NonNull KeyguardState keyguardState) {
+ Objects.requireNonNull(keyguardState);
+ final HierarchyOp hierarchyOp =
+ new HierarchyOp.Builder(
+ HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE)
+ .setKeyguardState(keyguardState)
+ .build();
+ mHierarchyOps.add(hierarchyOp);
+ return this;
+ }
+
+ /**
* Sets/removes the always on top flag for this {@code windowContainer}. See
* {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
* Please note that this method is only intended to be used for a
@@ -1469,6 +1487,7 @@
public static final int HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE = 19;
public static final int HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION = 20;
public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21;
+ public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1516,6 +1535,9 @@
private TaskFragmentOperation mTaskFragmentOperation;
@Nullable
+ private KeyguardState mKeyguardState;
+
+ @Nullable
private PendingIntent mPendingIntent;
@Nullable
@@ -1666,6 +1688,7 @@
mLaunchOptions = copy.mLaunchOptions;
mActivityIntent = copy.mActivityIntent;
mTaskFragmentOperation = copy.mTaskFragmentOperation;
+ mKeyguardState = copy.mKeyguardState;
mPendingIntent = copy.mPendingIntent;
mShortcutInfo = copy.mShortcutInfo;
mAlwaysOnTop = copy.mAlwaysOnTop;
@@ -1689,6 +1712,7 @@
mLaunchOptions = in.readBundle();
mActivityIntent = in.readTypedObject(Intent.CREATOR);
mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR);
+ mKeyguardState = in.readTypedObject(KeyguardState.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
mAlwaysOnTop = in.readBoolean();
@@ -1770,6 +1794,11 @@
}
@Nullable
+ public KeyguardState getKeyguardState() {
+ return mKeyguardState;
+ }
+
+ @Nullable
public PendingIntent getPendingIntent() {
return mPendingIntent;
}
@@ -1902,6 +1931,9 @@
.append(" mExcludeInsetsTypes= ")
.append(WindowInsets.Type.toString(mExcludeInsetsTypes));
break;
+ case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE:
+ sb.append("KeyguardState= ").append(mKeyguardState);
+ break;
case HIERARCHY_OP_TYPE_SET_IS_TRIMMABLE:
sb.append("container= ").append(mContainer)
.append(" isTrimmable= ")
@@ -1932,6 +1964,7 @@
dest.writeBundle(mLaunchOptions);
dest.writeTypedObject(mActivityIntent, flags);
dest.writeTypedObject(mTaskFragmentOperation, flags);
+ dest.writeTypedObject(mKeyguardState, flags);
dest.writeTypedObject(mPendingIntent, flags);
dest.writeTypedObject(mShortcutInfo, flags);
dest.writeBoolean(mAlwaysOnTop);
@@ -1993,6 +2026,9 @@
private TaskFragmentOperation mTaskFragmentOperation;
@Nullable
+ private KeyguardState mKeyguardState;
+
+ @Nullable
private PendingIntent mPendingIntent;
@Nullable
@@ -2081,6 +2117,12 @@
return this;
}
+ Builder setKeyguardState(
+ @Nullable KeyguardState keyguardState) {
+ mKeyguardState = keyguardState;
+ return this;
+ }
+
Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) {
mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch;
return this;
@@ -2130,6 +2172,7 @@
hierarchyOp.mPendingIntent = mPendingIntent;
hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
+ hierarchyOp.mKeyguardState = mKeyguardState;
hierarchyOp.mShortcutInfo = mShortcutInfo;
hierarchyOp.mBounds = mBounds;
hierarchyOp.mIncludingParents = mIncludingParents;
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index b22aa22..31bb3a6 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -319,4 +319,11 @@
namespace: "lse_desktop_experience"
description: "Enables custom transitions for alt-tab app launches in Desktop Mode."
bug: "370735595"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "enable_move_to_next_display_shortcut"
+ namespace: "lse_desktop_experience"
+ description: "Add new keyboard shortcut of moving a task into next display"
+ bug: "364154795"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index c9b93c9..622f8c8 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -173,6 +173,16 @@
}
flag {
+ name: "filter_irrelevant_input_device_change"
+ namespace: "windowing_frontend"
+ description: "Recompute display configuration only for necessary input device changes"
+ bug: "368461853"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "respect_non_top_visible_fixed_orientation"
namespace: "windowing_frontend"
description: "If top activity is not opaque, respect the fixed orientation of activity behind it"
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
index 0f8ced2..3557633 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
@@ -29,6 +29,7 @@
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
+import android.view.accessibility.Flags;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@@ -58,13 +59,15 @@
@NonNull View.OnClickListener uninstallListener) {
final AlertDialog ad = new AlertDialog.Builder(context)
.setView(createAccessibilityServiceWarningDialogContentView(
- context, info, allowListener, denyListener, uninstallListener))
+ context, info, allowListener, denyListener, uninstallListener))
.setCancelable(true)
.create();
Window window = ad.getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.privateFlags |= SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
- params.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+ if (!Flags.warningUseDefaultDialogType()) {
+ params.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+ }
window.setAttributes(params);
return ad;
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6faea17..bd746d5 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -38,8 +38,8 @@
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.flags.Flags.customizableWindowHeaders;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index c0a7383..e65b4b6 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -16,19 +16,14 @@
package com.android.internal.widget;
-import static java.lang.Float.NaN;
-
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Path;
-import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.graphics.Region;
import android.hardware.input.InputManager;
@@ -70,14 +65,11 @@
private static final PointerState EMPTY_POINTER_STATE = new PointerState();
public static class PointerState {
- private float mCurrentX = NaN;
- private float mCurrentY = NaN;
- private float mPreviousX = NaN;
- private float mPreviousY = NaN;
- private float mFirstX = NaN;
- private float mFirstY = NaN;
- private boolean mPreviousPointIsHistorical;
- private boolean mCurrentPointIsHistorical;
+ // Trace of previous points.
+ private float[] mTraceX = new float[32];
+ private float[] mTraceY = new float[32];
+ private boolean[] mTraceCurrent = new boolean[32];
+ private int mTraceCount;
// True if the pointer is down.
@UnsupportedAppUsage
@@ -104,20 +96,31 @@
public PointerState() {
}
- public void addTrace(float x, float y, boolean isHistorical) {
- if (Float.isNaN(mFirstX)) {
- mFirstX = x;
- }
- if (Float.isNaN(mFirstY)) {
- mFirstY = y;
+ public void clearTrace() {
+ mTraceCount = 0;
+ }
+
+ public void addTrace(float x, float y, boolean current) {
+ int traceCapacity = mTraceX.length;
+ if (mTraceCount == traceCapacity) {
+ traceCapacity *= 2;
+ float[] newTraceX = new float[traceCapacity];
+ System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount);
+ mTraceX = newTraceX;
+
+ float[] newTraceY = new float[traceCapacity];
+ System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount);
+ mTraceY = newTraceY;
+
+ boolean[] newTraceCurrent = new boolean[traceCapacity];
+ System.arraycopy(mTraceCurrent, 0, newTraceCurrent, 0, mTraceCount);
+ mTraceCurrent= newTraceCurrent;
}
- mPreviousX = mCurrentX;
- mPreviousY = mCurrentY;
- mCurrentX = x;
- mCurrentY = y;
- mPreviousPointIsHistorical = mCurrentPointIsHistorical;
- mCurrentPointIsHistorical = isHistorical;
+ mTraceX[mTraceCount] = x;
+ mTraceY[mTraceCount] = y;
+ mTraceCurrent[mTraceCount] = current;
+ mTraceCount += 1;
}
}
@@ -146,12 +149,6 @@
private final SparseArray<PointerState> mPointers = new SparseArray<PointerState>();
private final PointerCoords mTempCoords = new PointerCoords();
- // Draw the trace of all pointers in the current gesture in a separate layer
- // that is not cleared on every frame so that we don't have to re-draw the
- // entire trace on each frame.
- private final Bitmap mTraceBitmap;
- private final Canvas mTraceCanvas;
-
private final Region mSystemGestureExclusion = new Region();
private final Region mSystemGestureExclusionRejected = new Region();
private final Path mSystemGestureExclusionPath = new Path();
@@ -200,10 +197,6 @@
mPathPaint.setARGB(255, 0, 96, 255);
mPathPaint.setStyle(Paint.Style.STROKE);
- mTraceBitmap = Bitmap.createBitmap(getResources().getDisplayMetrics().widthPixels,
- getResources().getDisplayMetrics().heightPixels, Bitmap.Config.ARGB_8888);
- mTraceCanvas = new Canvas(mTraceBitmap);
-
configureDensityDependentFactors();
mSystemGestureExclusionPaint = new Paint();
@@ -263,7 +256,7 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mTextPaint.getFontMetricsInt(mTextMetrics);
- mHeaderBottom = mHeaderPaddingTop - mTextMetrics.ascent + mTextMetrics.descent + 2;
+ mHeaderBottom = mHeaderPaddingTop-mTextMetrics.ascent+mTextMetrics.descent+2;
if (false) {
Log.i("foo", "Metrics: ascent=" + mTextMetrics.ascent
+ " descent=" + mTextMetrics.descent
@@ -276,7 +269,6 @@
// Draw an oval. When angle is 0 radians, orients the major axis vertically,
// angles less than or greater than 0 radians rotate the major axis left or right.
private RectF mReusableOvalRect = new RectF();
-
private void drawOval(Canvas canvas, float x, float y, float major, float minor,
float angle, Paint paint) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
@@ -293,8 +285,6 @@
protected void onDraw(Canvas canvas) {
final int NP = mPointers.size();
- canvas.drawBitmap(mTraceBitmap, 0, 0, null);
-
if (!mSystemGestureExclusion.isEmpty()) {
mSystemGestureExclusionPath.reset();
mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath);
@@ -313,9 +303,32 @@
// Pointer trace.
for (int p = 0; p < NP; p++) {
final PointerState ps = mPointers.valueAt(p);
- float lastX = ps.mCurrentX, lastY = ps.mCurrentY;
- if (!Float.isNaN(lastX) && !Float.isNaN(lastY)) {
+ // Draw path.
+ final int N = ps.mTraceCount;
+ float lastX = 0, lastY = 0;
+ boolean haveLast = false;
+ boolean drawn = false;
+ mPaint.setARGB(255, 128, 255, 255);
+ for (int i=0; i < N; i++) {
+ float x = ps.mTraceX[i];
+ float y = ps.mTraceY[i];
+ if (Float.isNaN(x) || Float.isNaN(y)) {
+ haveLast = false;
+ continue;
+ }
+ if (haveLast) {
+ canvas.drawLine(lastX, lastY, x, y, mPathPaint);
+ final Paint paint = ps.mTraceCurrent[i - 1] ? mCurrentPointPaint : mPaint;
+ canvas.drawPoint(lastX, lastY, paint);
+ drawn = true;
+ }
+ lastX = x;
+ lastY = y;
+ haveLast = true;
+ }
+
+ if (drawn) {
// Draw velocity vector.
mPaint.setARGB(255, 255, 64, 128);
float xVel = ps.mXVelocity * (1000 / 60);
@@ -340,7 +353,7 @@
Math.max(getHeight(), getWidth()), mTargetPaint);
// Draw current point.
- int pressureLevel = (int) (ps.mCoords.pressure * 255);
+ int pressureLevel = (int)(ps.mCoords.pressure * 255);
mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel);
canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint);
@@ -411,7 +424,8 @@
.append(" / ").append(mMaxNumPointers)
.toString(), 1, base, mTextPaint);
- if ((mCurDown && ps.mCurDown) || Float.isNaN(ps.mCurrentX)) {
+ final int count = ps.mTraceCount;
+ if ((mCurDown && ps.mCurDown) || count == 0) {
canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
mTextBackgroundPaint);
canvas.drawText(mText.clear()
@@ -423,8 +437,8 @@
.append("Y: ").append(ps.mCoords.y, 1)
.toString(), 1 + itemW * 2, base, mTextPaint);
} else {
- float dx = ps.mCurrentX - ps.mFirstX;
- float dy = ps.mCurrentY - ps.mFirstY;
+ float dx = ps.mTraceX[count - 1] - ps.mTraceX[0];
+ float dy = ps.mTraceY[count - 1] - ps.mTraceY[0];
canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom,
Math.abs(dx) < mVC.getScaledTouchSlop()
? mTextBackgroundPaint : mTextLevelPaint);
@@ -551,9 +565,9 @@
.append(" TouchMinor=").append(coords.touchMinor, 3)
.append(" ToolMajor=").append(coords.toolMajor, 3)
.append(" ToolMinor=").append(coords.toolMinor, 3)
- .append(" Orientation=").append((float) (coords.orientation * 180 / Math.PI), 1)
+ .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1)
.append("deg")
- .append(" Tilt=").append((float) (
+ .append(" Tilt=").append((float)(
coords.getAxisValue(MotionEvent.AXIS_TILT) * 180 / Math.PI), 1)
.append("deg")
.append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1)
@@ -584,7 +598,6 @@
mCurNumPointers = 0;
mMaxNumPointers = 0;
mVelocity.clear();
- mTraceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
if (mAltVelocity != null) {
mAltVelocity.clear();
}
@@ -633,8 +646,7 @@
logCoords("Pointer", action, i, coords, id, event);
}
if (ps != null) {
- ps.addTrace(coords.x, coords.y, true);
- updateDrawTrace(ps);
+ ps.addTrace(coords.x, coords.y, false);
}
}
}
@@ -647,8 +659,7 @@
logCoords("Pointer", action, i, coords, id, event);
}
if (ps != null) {
- ps.addTrace(coords.x, coords.y, false);
- updateDrawTrace(ps);
+ ps.addTrace(coords.x, coords.y, true);
ps.mXVelocity = mVelocity.getXVelocity(id);
ps.mYVelocity = mVelocity.getYVelocity(id);
if (mAltVelocity != null) {
@@ -691,26 +702,13 @@
if (mActivePointerId == id) {
mActivePointerId = event.getPointerId(index == 0 ? 1 : 0);
}
- ps.addTrace(Float.NaN, Float.NaN, true);
+ ps.addTrace(Float.NaN, Float.NaN, false);
}
}
invalidate();
}
- private void updateDrawTrace(PointerState ps) {
- mPaint.setARGB(255, 128, 255, 255);
- float x = ps.mCurrentX;
- float y = ps.mCurrentY;
- float lastX = ps.mPreviousX;
- float lastY = ps.mPreviousY;
- if (!Float.isNaN(x) && !Float.isNaN(y) && !Float.isNaN(lastX) && !Float.isNaN(lastY)) {
- mTraceCanvas.drawLine(lastX, lastY, x, y, mPathPaint);
- Paint paint = ps.mPreviousPointIsHistorical ? mPaint : mCurrentPointPaint;
- mTraceCanvas.drawPoint(lastX, lastY, paint);
- }
- }
-
@Override
public boolean onTouchEvent(MotionEvent event) {
onPointerEvent(event);
@@ -769,7 +767,7 @@
return true;
default:
return KeyEvent.isGamepadButton(keyCode)
- || KeyEvent.isModifierKey(keyCode);
+ || KeyEvent.isModifierKey(keyCode);
}
}
@@ -889,7 +887,7 @@
public FasterStringBuilder append(int value, int zeroPadWidth) {
final boolean negative = value < 0;
if (negative) {
- value = -value;
+ value = - value;
if (value < 0) {
append("-2147483648");
return this;
@@ -975,27 +973,26 @@
private ISystemGestureExclusionListener mSystemGestureExclusionListener =
new ISystemGestureExclusionListener.Stub() {
- @Override
- public void onSystemGestureExclusionChanged(int displayId,
- Region systemGestureExclusion,
- Region systemGestureExclusionUnrestricted) {
- Region exclusion = Region.obtain(systemGestureExclusion);
- Region rejected = Region.obtain();
- if (systemGestureExclusionUnrestricted != null) {
- rejected.set(systemGestureExclusionUnrestricted);
- rejected.op(exclusion, Region.Op.DIFFERENCE);
- }
- Handler handler = getHandler();
- if (handler != null) {
- handler.post(() -> {
- mSystemGestureExclusion.set(exclusion);
- mSystemGestureExclusionRejected.set(rejected);
- exclusion.recycle();
- invalidate();
- });
- }
- }
- };
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion,
+ Region systemGestureExclusionUnrestricted) {
+ Region exclusion = Region.obtain(systemGestureExclusion);
+ Region rejected = Region.obtain();
+ if (systemGestureExclusionUnrestricted != null) {
+ rejected.set(systemGestureExclusionUnrestricted);
+ rejected.op(exclusion, Region.Op.DIFFERENCE);
+ }
+ Handler handler = getHandler();
+ if (handler != null) {
+ handler.post(() -> {
+ mSystemGestureExclusion.set(exclusion);
+ mSystemGestureExclusionRejected.set(rejected);
+ exclusion.recycle();
+ invalidate();
+ });
+ }
+ }
+ };
@Override
protected void onConfigurationChanged(Configuration newConfig) {
diff --git a/core/proto/android/widget/remoteviews.proto b/core/proto/android/widget/remoteviews.proto
index f477d32..6a987a4 100644
--- a/core/proto/android/widget/remoteviews.proto
+++ b/core/proto/android/widget/remoteviews.proto
@@ -32,6 +32,8 @@
*
* Do not change the tag number or type of any fields in order to maintain compatibility with
* previous versions. If a field is deleted, use `reserved` to mark its tag number.
+ *
+ * Next tag: 17
*/
message RemoteViewsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -290,6 +292,7 @@
}
}
+ // Next tag: 23
message Action {
oneof action {
AttributeReflectionAction attribute_reflection_action = 1;
@@ -307,6 +310,13 @@
SetRadioGroupCheckedAction set_radio_group_checked_action = 13;
SetRemoteCollectionItemListAdapterAction set_remote_collection_item_list_adapter_action = 14;
SetRippleDrawableColorAction set_ripple_drawable_color_action = 15;
+ SetViewOutlinePreferredRadiusAction set_view_outline_preferred_radius_action = 16;
+ TextViewDrawableAction text_view_drawable_action = 17;
+ TextViewSizeAction text_view_size_action = 18;
+ ViewGroupAddAction view_group_add_action = 19;
+ ViewGroupRemoveAction view_group_remove_action = 20;
+ ViewPaddingAction view_padding_action = 21;
+ SetDrawInstructionAction set_draw_instruction_action = 22;
}
}
@@ -428,6 +438,65 @@
optional string view_id = 1;
optional android.content.res.ColorStateListProto color_state_list = 2;
}
+
+ message SetViewOutlinePreferredRadiusAction {
+ optional string view_id = 1;
+ optional int32 value_type = 2;
+ optional int32 value = 3;
+ }
+
+ message TextViewDrawableAction {
+ optional string view_id = 1;
+ optional bool is_relative = 2;
+ oneof drawables {
+ Resources resources = 3;
+ Icons icons = 4;
+ };
+
+ message Resources {
+ optional string one = 1;
+ optional string two = 2;
+ optional string three = 3;
+ optional string four = 4;
+ }
+
+ message Icons {
+ optional Icon one = 1;
+ optional Icon two = 2;
+ optional Icon three = 3;
+ optional Icon four = 4;
+ }
+ }
+
+ message TextViewSizeAction {
+ optional string view_id = 1;
+ optional int32 units = 2;
+ optional float size = 3;
+ }
+
+ message ViewGroupAddAction {
+ optional string view_id = 1;
+ optional RemoteViewsProto nested_views = 2;
+ optional int32 index = 3;
+ optional int32 stableId = 4;
+ }
+
+ message ViewGroupRemoveAction {
+ optional string view_id = 1;
+ optional string view_id_to_keep = 2;
+ }
+
+ message ViewPaddingAction {
+ optional string view_id = 1;
+ optional int32 left = 2;
+ optional int32 right = 3;
+ optional int32 top = 4;
+ optional int32 bottom = 5;
+ }
+
+ message SetDrawInstructionAction {
+ repeated bytes instructions = 1;
+ }
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b90ee2b..8a2d767 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6918,6 +6918,14 @@
entering the corresponding modes -->
<string name="config_rearDisplayPhysicalAddress" translatable="false"></string>
+ <!-- The maximum number of virtual displays that can exist at the same time.
+ It must be >= 1. -->
+ <integer name="config_virtualDisplayLimit">100</integer>
+
+ <!-- The maximum number of virtual displays per package that can exist at the same time.
+ It must be >= 1. -->
+ <integer name="config_virtualDisplayLimitPerPackage">50</integer>
+
<!-- List of certificate to be used for font fs-verity integrity verification -->
<string-array translatable="false" name="config_fontManagerServiceCerts">
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b7c8765..c1893ab 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5240,6 +5240,9 @@
<java-symbol type="integer" name="config_deviceStateConcurrentRearDisplay" />
<java-symbol type="string" name="config_rearDisplayPhysicalAddress" />
+ <java-symbol type="integer" name="config_virtualDisplayLimit" />
+ <java-symbol type="integer" name="config_virtualDisplayLimitPerPackage" />
+
<!-- For app language picker -->
<java-symbol type="string" name="system_locale_title" />
<java-symbol type="layout" name="app_language_picker_system_default" />
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index b16c237..be8ecbe 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -470,6 +470,7 @@
@Test
@SmallTest
+ @DisabledOnRavenwood(blockedBy = ResourcesManager.class)
public void testResourceConfigurationAppliedWhenOverrideDoesNotExist() {
final int width = 240;
final int height = 360;
diff --git a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java b/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java
similarity index 88%
rename from core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
rename to core/tests/coretests/src/android/window/DesktopModeFlagsTest.java
index a311d0d..b28e2b0 100644
--- a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
+++ b/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package android.window.flags;
+package android.window;
-import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_ON;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET;
-import static android.window.flags.DesktopModeFlags.ToggleOverride.fromSetting;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE;
+import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF;
+import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON;
+import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET;
+import static android.window.DesktopModeFlags.ToggleOverride.fromSetting;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS;
@@ -40,6 +41,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -48,7 +50,7 @@
import java.lang.reflect.Field;
/**
- * Test class for {@link DesktopModeFlags}
+ * Test class for {@link android.window.DesktopModeFlags}
*
* Build/Install/Run:
* atest FrameworksCoreTests:DesktopModeFlagsTest
@@ -68,8 +70,12 @@
private static final int OVERRIDE_UNSET_SETTING = -1;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
+ @After
+ public void tearDown() throws Exception {
resetCache();
}
@@ -203,7 +209,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@@ -212,7 +218,7 @@
public void isTrue_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@@ -225,7 +231,7 @@
setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@@ -235,7 +241,7 @@
setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@@ -248,7 +254,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@@ -258,7 +264,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@@ -271,7 +277,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@@ -284,7 +290,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@@ -297,7 +303,7 @@
setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@@ -310,7 +316,7 @@
setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@@ -323,7 +329,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue();
}
@Test
@@ -336,7 +342,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse();
}
@Test
@@ -375,5 +381,6 @@
"sCachedToggleOverride");
cachedToggleOverride.setAccessible(true);
cachedToggleOverride.set(null, null);
+ setOverride(OVERRIDE_UNSET_SETTING);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
index 362eeea..8e906fd 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
@@ -25,6 +25,8 @@
import android.app.AlertDialog;
import android.content.Context;
import android.os.RemoteException;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.AndroidTestingRunner;
@@ -33,6 +35,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
+import android.view.accessibility.Flags;
import android.widget.TextView;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -89,7 +92,19 @@
}
@Test
- public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams() {
+ @RequiresFlagsDisabled(Flags.FLAG_WARNING_USE_DEFAULT_DIALOG_TYPE)
+ public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams_isSystemDialog() {
+ createAccessibilityServiceWarningDialog_hasExpectedWindowParams(true);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_WARNING_USE_DEFAULT_DIALOG_TYPE)
+ public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams_notSystemDialog() {
+ createAccessibilityServiceWarningDialog_hasExpectedWindowParams(false);
+ }
+
+ private void createAccessibilityServiceWarningDialog_hasExpectedWindowParams(
+ boolean expectSystemDialog) {
final AlertDialog dialog =
AccessibilityServiceWarning.createAccessibilityServiceWarningDialog(
mContext,
@@ -101,7 +116,11 @@
expect.that(dialogWindow.getAttributes().privateFlags
& SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
- expect.that(dialogWindow.getAttributes().type).isEqualTo(TYPE_SYSTEM_DIALOG);
+ if (expectSystemDialog) {
+ expect.that(dialogWindow.getAttributes().type).isEqualTo(TYPE_SYSTEM_DIALOG);
+ } else {
+ expect.that(dialogWindow.getAttributes().type).isNotEqualTo(TYPE_SYSTEM_DIALOG);
+ }
}
@Test
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index a3303c6..a2aa62d 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -26,11 +26,12 @@
// Include all test java files
srcs: ["src/**/*.java"],
static_libs: [
+ "androidx.test.ext.junit",
"androidx.test.rules",
"frameworks-base-testutils",
"mockito-target-minus-junit4",
"platform-test-annotations",
- "testng",
+ "truth",
],
libs: ["android.test.runner.stubs.system"],
platform_apis: true,
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
index cf7c549..1b78433 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
@@ -22,21 +22,15 @@
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;
import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.os.Parcel;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.List;
@@ -44,13 +38,13 @@
/**
* Unit tests for {@link DeviceStateInfo}.
- * <p/>
- * Run with <code>atest DeviceStateInfoTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksCoreDeviceStateManagerTests:DeviceStateInfoTest
*/
-@RunWith(JUnit4.class)
@SmallTest
+@RunWith(AndroidJUnit4.class)
public final class DeviceStateInfoTest {
-
private static final DeviceState DEVICE_STATE_0 = new DeviceState(
new DeviceState.Configuration.Builder(0, "STATE_0")
.setSystemProperties(
@@ -74,88 +68,113 @@
@Test
public void create() {
- final ArrayList<DeviceState> supportedStates = new ArrayList<>(
- List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+ final ArrayList<DeviceState> supportedStates =
+ new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
final DeviceState baseState = DEVICE_STATE_0;
final DeviceState currentState = DEVICE_STATE_2;
- final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
- assertNotNull(info.supportedStates);
- assertEquals(supportedStates, info.supportedStates);
- assertEquals(baseState, info.baseState);
- assertEquals(currentState, info.currentState);
+ final DeviceStateInfo info =
+ new DeviceStateInfo(supportedStates, baseState, currentState);
+
+ assertThat(info.supportedStates).containsExactlyElementsIn(supportedStates).inOrder();
+ assertThat(info.baseState).isEqualTo(baseState);
+ assertThat(info.currentState).isEqualTo(currentState);
}
@Test
public void equals() {
- final ArrayList<DeviceState> supportedStates = new ArrayList<>(
- List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+ final ArrayList<DeviceState> supportedStates =
+ new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
final DeviceState baseState = DEVICE_STATE_0;
final DeviceState currentState = DEVICE_STATE_2;
final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
- Assert.assertEquals(info, info);
+ final DeviceStateInfo sameInstance = info;
+ assertThat(info).isEqualTo(sameInstance);
- final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
- currentState);
- Assert.assertEquals(info, sameInfo);
+ final DeviceStateInfo sameInfo =
+ new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertThat(info).isEqualTo(sameInfo);
+
+ final DeviceStateInfo copiedInfo = new DeviceStateInfo(info);
+ assertThat(info).isEqualTo(copiedInfo);
final DeviceStateInfo differentInfo = new DeviceStateInfo(
new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_2)), baseState, currentState);
- assertNotEquals(info, differentInfo);
+ assertThat(differentInfo).isNotEqualTo(info);
+ }
+
+ @Test
+ public void hashCode_sameObject() {
+ final ArrayList<DeviceState> supportedStates =
+ new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+ final DeviceState baseState = DEVICE_STATE_0;
+ final DeviceState currentState = DEVICE_STATE_2;
+ final DeviceStateInfo info =
+ new DeviceStateInfo(supportedStates, baseState, currentState);
+ final DeviceStateInfo copiedInfo = new DeviceStateInfo(info);
+
+ assertThat(info.hashCode()).isEqualTo(copiedInfo.hashCode());
}
@Test
public void diff_sameObject() {
- final ArrayList<DeviceState> supportedStates = new ArrayList<>(
- List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+ final ArrayList<DeviceState> supportedStates =
+ new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
final DeviceState baseState = DEVICE_STATE_0;
final DeviceState currentState = DEVICE_STATE_2;
final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
- assertEquals(0, info.diff(info));
+
+ assertThat(info.diff(info)).isEqualTo(0);
}
@Test
public void diff_differentSupportedStates() {
- final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
- DEVICE_STATE_0, DEVICE_STATE_0);
+ final DeviceStateInfo info = new DeviceStateInfo(
+ new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_0);
final DeviceStateInfo otherInfo = new DeviceStateInfo(
new ArrayList<>(List.of(DEVICE_STATE_2)), DEVICE_STATE_0, DEVICE_STATE_0);
+
final int diff = info.diff(otherInfo);
- assertTrue((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
- assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
- assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+
+ assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isGreaterThan(0);
+ assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isEqualTo(0);
+ assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isEqualTo(0);
}
@Test
public void diff_differentNonOverrideState() {
- final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
- DEVICE_STATE_1, DEVICE_STATE_0);
+ final DeviceStateInfo info = new DeviceStateInfo(
+ new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_1, DEVICE_STATE_0);
final DeviceStateInfo otherInfo = new DeviceStateInfo(
new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_2, DEVICE_STATE_0);
+
final int diff = info.diff(otherInfo);
- assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
- assertTrue((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
- assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+
+ assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isEqualTo(0);
+ assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isGreaterThan(0);
+ assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isEqualTo(0);
}
@Test
public void diff_differentState() {
- final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
- DEVICE_STATE_0, DEVICE_STATE_1);
+ final DeviceStateInfo info = new DeviceStateInfo(
+ new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_1);
final DeviceStateInfo otherInfo = new DeviceStateInfo(
new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_2);
+
final int diff = info.diff(otherInfo);
- assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
- assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
- assertTrue((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+
+ assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isEqualTo(0);
+ assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isEqualTo(0);
+ assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isGreaterThan(0);
}
@Test
public void writeToParcel() {
- final ArrayList<DeviceState> supportedStates = new ArrayList<>(
- List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
+ final ArrayList<DeviceState> supportedStates =
+ new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
final DeviceState nonOverrideState = DEVICE_STATE_0;
final DeviceState state = DEVICE_STATE_2;
final DeviceStateInfo originalInfo =
@@ -166,6 +185,6 @@
parcel.setDataPosition(0);
final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
- assertEquals(originalInfo, info);
+ assertThat(info).isEqualTo(originalInfo);
}
}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index f4d3631..7c01ecc 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,8 +16,7 @@
package android.hardware.devicestate;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -31,6 +30,9 @@
import android.os.RemoteException;
import android.os.test.FakePermissionEnforcer;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.util.ConcurrentUtils;
@@ -38,7 +40,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.HashSet;
@@ -47,32 +48,35 @@
/**
* Unit tests for {@link DeviceStateManagerGlobal}.
- * <p/>
- * Run with <code>atest DeviceStateManagerGlobalTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksCoreDeviceStateManagerTests:DeviceStateManagerGlobalTest
*/
-@RunWith(JUnit4.class)
@SmallTest
+@RunWith(AndroidJUnit4.class)
public final class DeviceStateManagerGlobalTest {
private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(
new DeviceState.Configuration.Builder(0 /* identifier */, "" /* name */).build());
private static final DeviceState OTHER_DEVICE_STATE = new DeviceState(
new DeviceState.Configuration.Builder(1 /* identifier */, "" /* name */).build());
+ @NonNull
private TestDeviceStateManagerService mService;
+ @NonNull
private DeviceStateManagerGlobal mDeviceStateManagerGlobal;
@Before
public void setUp() {
- FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
+ final FakePermissionEnforcer permissionEnforcer = new FakePermissionEnforcer();
mService = new TestDeviceStateManagerService(permissionEnforcer);
mDeviceStateManagerGlobal = new DeviceStateManagerGlobal(mService);
- assertFalse(mService.mCallbacks.isEmpty());
+ assertThat(mService.mCallbacks).isNotEmpty();
}
@Test
public void registerCallback() {
- DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
- DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
+ final DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+ final DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
ConcurrentUtils.DIRECT_EXECUTOR);
@@ -105,8 +109,8 @@
reset(callback2);
// Change the requested state and verify callback
- DeviceStateRequest request = DeviceStateRequest.newBuilder(
- DEFAULT_DEVICE_STATE.getIdentifier()).build();
+ final DeviceStateRequest request =
+ DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE.getIdentifier()).build();
mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
verify(callback1).onDeviceStateChanged(eq(mService.getMergedState()));
@@ -115,10 +119,10 @@
@Test
public void unregisterCallback() {
- DeviceStateCallback callback = mock(DeviceStateCallback.class);
+ final DeviceStateCallback callback = mock(DeviceStateCallback.class);
- mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
- ConcurrentUtils.DIRECT_EXECUTOR);
+ mDeviceStateManagerGlobal
+ .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
// Verify initial callbacks
verify(callback).onSupportedStatesChanged(eq(mService.getSupportedDeviceStates()));
@@ -134,15 +138,15 @@
@Test
public void submitRequest() {
- DeviceStateCallback callback = mock(DeviceStateCallback.class);
- mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
- ConcurrentUtils.DIRECT_EXECUTOR);
+ final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+ mDeviceStateManagerGlobal
+ .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
reset(callback);
- DeviceStateRequest request = DeviceStateRequest.newBuilder(
- OTHER_DEVICE_STATE.getIdentifier()).build();
+ final DeviceStateRequest request =
+ DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
verify(callback).onDeviceStateChanged(eq(OTHER_DEVICE_STATE));
@@ -155,15 +159,15 @@
@Test
public void submitBaseStateOverrideRequest() {
- DeviceStateCallback callback = mock(DeviceStateCallback.class);
- mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
- ConcurrentUtils.DIRECT_EXECUTOR);
+ final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+ mDeviceStateManagerGlobal
+ .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
reset(callback);
- DeviceStateRequest request = DeviceStateRequest.newBuilder(
- OTHER_DEVICE_STATE.getIdentifier()).build();
+ final DeviceStateRequest request =
+ DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
mDeviceStateManagerGlobal.requestBaseStateOverride(request, null /* executor */,
null /* callback */);
@@ -177,28 +181,28 @@
@Test
public void submitBaseAndEmulatedStateOverride() {
- DeviceStateCallback callback = mock(DeviceStateCallback.class);
- mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
- ConcurrentUtils.DIRECT_EXECUTOR);
+ final DeviceStateCallback callback = mock(DeviceStateCallback.class);
+ mDeviceStateManagerGlobal
+ .registerDeviceStateCallback(callback, ConcurrentUtils.DIRECT_EXECUTOR);
verify(callback).onDeviceStateChanged(eq(mService.getBaseState()));
reset(callback);
- DeviceStateRequest request = DeviceStateRequest.newBuilder(
- OTHER_DEVICE_STATE.getIdentifier()).build();
+ final DeviceStateRequest request =
+ DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
mDeviceStateManagerGlobal.requestBaseStateOverride(request, null /* executor */,
null /* callback */);
verify(callback).onDeviceStateChanged(eq(OTHER_DEVICE_STATE));
- assertEquals(OTHER_DEVICE_STATE, mService.getBaseState());
+ assertThat(mService.getBaseState()).isEqualTo(OTHER_DEVICE_STATE);
reset(callback);
- DeviceStateRequest secondRequest = DeviceStateRequest.newBuilder(
- DEFAULT_DEVICE_STATE.getIdentifier()).build();
+ final DeviceStateRequest secondRequest =
+ DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE.getIdentifier()).build();
mDeviceStateManagerGlobal.requestState(secondRequest, null, null);
- assertEquals(OTHER_DEVICE_STATE, mService.getBaseState());
+ assertThat(mService.getBaseState()).isEqualTo(OTHER_DEVICE_STATE);
verify(callback).onDeviceStateChanged(eq(DEFAULT_DEVICE_STATE));
reset(callback);
@@ -214,10 +218,10 @@
@Test
public void verifyDeviceStateRequestCallbacksCalled() {
- DeviceStateRequest.Callback callback = mock(TestDeviceStateRequestCallback.class);
+ final DeviceStateRequest.Callback callback = mock(TestDeviceStateRequestCallback.class);
- DeviceStateRequest request = DeviceStateRequest.newBuilder(
- OTHER_DEVICE_STATE.getIdentifier()).build();
+ final DeviceStateRequest request =
+ DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE.getIdentifier()).build();
mDeviceStateManagerGlobal.requestState(request,
ConcurrentUtils.DIRECT_EXECUTOR /* executor */,
callback /* callback */);
@@ -232,52 +236,55 @@
public static class TestDeviceStateRequestCallback implements DeviceStateRequest.Callback {
@Override
- public void onRequestActivated(DeviceStateRequest request) { }
+ public void onRequestActivated(@NonNull DeviceStateRequest request) { }
@Override
- public void onRequestCanceled(DeviceStateRequest request) { }
+ public void onRequestCanceled(@NonNull DeviceStateRequest request) { }
@Override
- public void onRequestSuspended(DeviceStateRequest request) { }
+ public void onRequestSuspended(@NonNull DeviceStateRequest request) { }
}
private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
- public static final class Request {
- public final IBinder token;
- public final int state;
- public final int flags;
+ static final class Request {
+ @NonNull
+ final IBinder mToken;
+ final int mState;
- private Request(IBinder token, int state, int flags) {
- this.token = token;
- this.state = state;
- this.flags = flags;
+ private Request(@NonNull IBinder token, int state) {
+ this.mToken = token;
+ this.mState = state;
}
}
- private List<DeviceState> mSupportedDeviceStates = List.of(DEFAULT_DEVICE_STATE,
- OTHER_DEVICE_STATE);
-
+ @NonNull
+ private List<DeviceState> mSupportedDeviceStates =
+ List.of(DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE);
+ @NonNull
private DeviceState mBaseState = DEFAULT_DEVICE_STATE;
+ @Nullable
private Request mRequest;
+ @Nullable
private Request mBaseStateRequest;
private final Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
- TestDeviceStateManagerService(FakePermissionEnforcer enforcer) {
+ TestDeviceStateManagerService(@NonNull FakePermissionEnforcer enforcer) {
super(enforcer);
}
+ @NonNull
private DeviceStateInfo getInfo() {
final int mergedBaseState = mBaseStateRequest == null
- ? mBaseState.getIdentifier() : mBaseStateRequest.state;
- final int mergedState = mRequest == null
- ? mergedBaseState : mRequest.state;
+ ? mBaseState.getIdentifier() : mBaseStateRequest.mState;
+ final int mergedState = mRequest == null ? mergedBaseState : mRequest.mState;
+ final ArrayList<DeviceState> supportedStates = new ArrayList<>(mSupportedDeviceStates);
final DeviceState baseState = new DeviceState(
new DeviceState.Configuration.Builder(mergedBaseState, "" /* name */).build());
final DeviceState state = new DeviceState(
new DeviceState.Configuration.Builder(mergedState, "" /* name */).build());
- return new DeviceStateInfo(new ArrayList<>(mSupportedDeviceStates), baseState, state);
+ return new DeviceStateInfo(supportedStates, baseState, state);
}
private void notifyDeviceStateInfoChanged() {
@@ -291,6 +298,7 @@
}
}
+ @NonNull
@Override
public DeviceStateInfo getDeviceStateInfo() {
return getInfo();
@@ -311,18 +319,18 @@
}
@Override
- public void requestState(IBinder token, int state, int flags) {
+ public void requestState(@NonNull IBinder token, int state, int unusedFlags) {
if (mRequest != null) {
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
- callback.onRequestCanceled(mRequest.token);
+ callback.onRequestCanceled(mRequest.mToken);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
}
- final Request request = new Request(token, state, flags);
+ final Request request = new Request(token, state);
mRequest = request;
notifyDeviceStateInfoChanged();
@@ -337,7 +345,7 @@
@Override
public void cancelStateRequest() {
- IBinder token = mRequest.token;
+ final IBinder token = mRequest.mToken;
mRequest = null;
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
@@ -350,19 +358,18 @@
}
@Override
- public void requestBaseStateOverride(IBinder token, int state, int flags) {
+ public void requestBaseStateOverride(@NonNull IBinder token, int state, int unusedFlags) {
if (mBaseStateRequest != null) {
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
- callback.onRequestCanceled(mBaseStateRequest.token);
+ callback.onRequestCanceled(mBaseStateRequest.mToken);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
}
- final Request request = new Request(token, state, flags);
- mBaseStateRequest = request;
+ mBaseStateRequest = new Request(token, state);
notifyDeviceStateInfoChanged();
for (IDeviceStateManagerCallback callback : mCallbacks) {
@@ -376,7 +383,7 @@
@Override
public void cancelBaseStateOverride() throws RemoteException {
- IBinder token = mBaseStateRequest.token;
+ final IBinder token = mBaseStateRequest.mToken;
mBaseStateRequest = null;
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
@@ -396,24 +403,27 @@
onStateRequestOverlayDismissed_enforcePermission();
}
- public void setSupportedStates(List<DeviceState> states) {
+ public void setSupportedStates(@NonNull List<DeviceState> states) {
mSupportedDeviceStates = states;
notifyDeviceStateInfoChanged();
}
+ @NonNull
public List<DeviceState> getSupportedDeviceStates() {
return mSupportedDeviceStates;
}
- public void setBaseState(DeviceState state) {
+ public void setBaseState(@NonNull DeviceState state) {
mBaseState = state;
notifyDeviceStateInfoChanged();
}
+ @NonNull
public DeviceState getBaseState() {
return getInfo().baseState;
}
+ @NonNull
public DeviceState getMergedState() {
return getInfo().currentState;
}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
index 78d4324..83b5ff3 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
@@ -21,17 +21,16 @@
import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS;
import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import junit.framework.Assert;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import java.util.HashSet;
import java.util.List;
@@ -39,28 +38,32 @@
/**
* Unit tests for {@link android.hardware.devicestate.DeviceState}.
- * <p/>
- * Run with <code>atest DeviceStateTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksCoreDeviceStateManagerTests:DeviceStateTest
*/
@Presubmit
-@RunWith(JUnit4.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
public final class DeviceStateTest {
@Test
public void testConstruct() {
- DeviceState.Configuration config = new DeviceState.Configuration.Builder(
+ final DeviceState.Configuration config = new DeviceState.Configuration.Builder(
MINIMUM_DEVICE_STATE_IDENTIFIER, "TEST_CLOSED")
.setSystemProperties(
new HashSet<>(List.of(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)))
.build();
+
final DeviceState state = new DeviceState(config);
- assertEquals(state.getIdentifier(), MINIMUM_DEVICE_STATE_IDENTIFIER);
- assertEquals(state.getName(), "TEST_CLOSED");
- assertTrue(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS));
+
+ assertThat(state.getIdentifier()).isEqualTo(MINIMUM_DEVICE_STATE_IDENTIFIER);
+ assertThat(state.getName()).isEqualTo("TEST_CLOSED");
+ assertThat(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)).isTrue();
}
@Test
public void testHasProperties() {
- DeviceState.Configuration config = new DeviceState.Configuration.Builder(
+ final DeviceState.Configuration config = new DeviceState.Configuration.Builder(
MINIMUM_DEVICE_STATE_IDENTIFIER, "TEST")
.setSystemProperties(new HashSet<>(List.of(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)))
@@ -68,10 +71,10 @@
final DeviceState state = new DeviceState(config);
- assertTrue(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS));
- assertTrue(state.hasProperty(PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST));
- assertTrue(state.hasProperties(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
- PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST));
+ assertThat(state.hasProperty(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS)).isTrue();
+ assertThat(state.hasProperty(PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)).isTrue();
+ assertThat(state.hasProperties(PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS,
+ PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)).isTrue();
}
@Test
@@ -91,7 +94,7 @@
final DeviceState.Configuration stateConfiguration =
DeviceState.Configuration.CREATOR.createFromParcel(parcel);
- Assert.assertEquals(originalState, new DeviceState(stateConfiguration));
+ assertThat(originalState).isEqualTo(new DeviceState(stateConfiguration));
}
@Test
@@ -109,6 +112,6 @@
final DeviceState.Configuration stateConfiguration =
DeviceState.Configuration.CREATOR.createFromParcel(parcel);
- Assert.assertEquals(originalState, new DeviceState(stateConfiguration));
+ assertThat(originalState).isEqualTo(new DeviceState(stateConfiguration));
}
}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index e493ed1..4642fe5 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -234,10 +234,6 @@
// *.kt sources are inside a filegroup.
"kotlin-annotations",
],
- required: [
- "wmshell.protolog.json.gz",
- "wmshell.protolog.pb",
- ],
flags_packages: [
"com_android_wm_shell_flags",
],
@@ -246,3 +242,11 @@
plugins: ["dagger2-compiler"],
use_resource_processor: true,
}
+
+java_defaults {
+ name: "wmshell_defaults",
+ required: [
+ "wmshell.protolog.json.gz",
+ "wmshell.protolog.pb",
+ ],
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java
index 26aae2d..02a7991 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/FocusTransitionListener.java
@@ -26,5 +26,11 @@
/**
* Called when a transition changes the top, focused display.
*/
- void onFocusedDisplayChanged(int displayId);
+ default void onFocusedDisplayChanged(int displayId) {}
+
+ /**
+ * Called when the per-app or system-wide focus state has changed for a task.
+ */
+ default void onFocusedTaskChanged(int taskId, boolean isFocusedOnDisplay,
+ boolean isFocusedGlobally) {}
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/FlyoutDrawableLoader.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/FlyoutDrawableLoader.kt
new file mode 100644
index 0000000..5a17330
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/FlyoutDrawableLoader.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.shared.bubbles
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.util.Log
+
+object FlyoutDrawableLoader {
+
+ private const val TAG = "FlyoutDrawableLoader"
+
+ /** Loads the flyout icon as a [Drawable]. */
+ @JvmStatic
+ fun Icon?.loadFlyoutDrawable(context: Context): Drawable? {
+ if (this == null) return null
+ try {
+ if (this.type == Icon.TYPE_URI || this.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ context.grantUriPermission(
+ context.packageName,
+ this.uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+ }
+ return loadDrawable(context)
+ } catch (e: Exception) {
+ Log.w(TAG, "loadFlyoutDrawable failed: ${e.message}")
+ return null
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 647a555a..0150bcd 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index c88a58b..1abe119 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -36,6 +36,8 @@
@VisibleForTesting
public enum Event implements UiEventLogger.UiEventEnum {
+ // region bubble events
+
@UiEvent(doc = "User dismissed the bubble via gesture, add bubble to overflow.")
BUBBLE_OVERFLOW_ADD_USER_GESTURE(483),
@@ -64,7 +66,89 @@
BUBBLE_OVERFLOW_SELECTED(600),
@UiEvent(doc = "Restore bubble to overflow after phone reboot.")
- BUBBLE_OVERFLOW_RECOVER(691);
+ BUBBLE_OVERFLOW_RECOVER(691),
+
+ // endregion
+
+ // region bubble bar events
+
+ @UiEvent(doc = "new bubble posted")
+ BUBBLE_BAR_BUBBLE_POSTED(1927),
+
+ @UiEvent(doc = "existing bubble updated")
+ BUBBLE_BAR_BUBBLE_UPDATED(1928),
+
+ @UiEvent(doc = "expanded a bubble from bubble bar")
+ BUBBLE_BAR_EXPANDED(1929),
+
+ @UiEvent(doc = "bubble bar collapsed")
+ BUBBLE_BAR_COLLAPSED(1930),
+
+ @UiEvent(doc = "dismissed single bubble from bubble bar by dragging it to dismiss target")
+ BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE(1931),
+
+ @UiEvent(doc = "dismissed single bubble from bubble bar by dragging the expanded view to "
+ + "dismiss target")
+ BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_EXP_VIEW(1932),
+
+ @UiEvent(doc = "dismiss bubble from app handle menu")
+ BUBBLE_BAR_BUBBLE_DISMISSED_APP_MENU(1933),
+
+ @UiEvent(doc = "bubble is dismissed due to app finishing the bubble activity")
+ BUBBLE_BAR_BUBBLE_ACTIVITY_FINISH(1934),
+
+ @UiEvent(doc = "dismissed the bubble bar by dragging it to dismiss target")
+ BUBBLE_BAR_DISMISSED_DRAG_BAR(1935),
+
+ @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging from the "
+ + "expanded view")
+ BUBBLE_BAR_MOVED_LEFT_DRAG_EXP_VIEW(1936),
+
+ @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging from a single"
+ + " bubble")
+ BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE(1937),
+
+ @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging the bubble bar")
+ BUBBLE_BAR_MOVED_LEFT_DRAG_BAR(1938),
+
+ @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging from the "
+ + "expanded view")
+ BUBBLE_BAR_MOVED_RIGHT_DRAG_EXP_VIEW(1939),
+
+ @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging from a "
+ + "single bubble")
+ BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE(1940),
+
+ @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging the bubble "
+ + "bar")
+ BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR(1941),
+
+ @UiEvent(doc = "stop bubbling conversation from app handle menu")
+ BUBBLE_BAR_APP_MENU_OPT_OUT(1942),
+
+ @UiEvent(doc = "open app settings from app handle menu")
+ BUBBLE_BAR_APP_MENU_GO_TO_SETTINGS(1943),
+
+ @UiEvent(doc = "flyout shown for a bubble")
+ BUBBLE_BAR_FLYOUT(1944),
+
+ @UiEvent(doc = "notification for the bubble was canceled")
+ BUBBLE_BAR_BUBBLE_REMOVED_CANCELED(1945),
+
+ @UiEvent(doc = "user turned off bubbles from settings")
+ BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED(1946),
+
+ @UiEvent(doc = "bubble bar overflow opened")
+ BUBBLE_BAR_OVERFLOW_SELECTED(1947),
+
+ @UiEvent(doc = "max number of bubbles was reached in bubble bar, move bubble to overflow")
+ BUBBLE_BAR_OVERFLOW_ADD_AGED(1948),
+
+ @UiEvent(doc = "bubble promoted from overflow back to bubble bar")
+ BUBBLE_BAR_OVERFLOW_REMOVE_BACK_TO_BAR(1949),
+
+ // endregion
+ ;
private final int mId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index c5e3afd..39fb2f49 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -21,11 +21,10 @@
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
+import static com.android.wm.shell.shared.bubbles.FlyoutDrawableLoader.loadFlyoutDrawable;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
@@ -34,7 +33,6 @@
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.util.Log;
import android.util.PathParser;
import android.view.LayoutInflater;
@@ -51,7 +49,6 @@
import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.lang.ref.WeakReference;
-import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -340,7 +337,7 @@
info.flyoutMessage = b.getFlyoutMessage();
if (info.flyoutMessage != null) {
info.flyoutMessage.senderAvatar =
- loadSenderAvatar(c, info.flyoutMessage.senderIcon);
+ loadFlyoutDrawable(info.flyoutMessage.senderIcon, c);
}
return info;
}
@@ -422,21 +419,4 @@
Color.WHITE, WHITE_SCRIM_ALPHA);
return true;
}
-
- @Nullable
- static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
- Objects.requireNonNull(context);
- if (icon == null) return null;
- try {
- if (icon.getType() == Icon.TYPE_URI
- || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
- context.grantUriPermission(context.getPackageName(),
- icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- return icon.loadDrawable(context);
- } catch (Exception e) {
- Log.w(TAG, "loadSenderAvatar failed: " + e.getMessage());
- return null;
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
index c12822a..e9a5933 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
@@ -20,11 +20,10 @@
import static com.android.wm.shell.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.shared.bubbles.FlyoutDrawableLoader.loadFlyoutDrawable;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
@@ -33,7 +32,6 @@
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.util.Log;
import android.util.PathParser;
@@ -50,7 +48,6 @@
import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.lang.ref.WeakReference;
-import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -264,7 +261,7 @@
info.flyoutMessage = b.getFlyoutMessage();
if (info.flyoutMessage != null) {
info.flyoutMessage.senderAvatar =
- loadSenderAvatar(c, info.flyoutMessage.senderIcon);
+ loadFlyoutDrawable(info.flyoutMessage.senderIcon, c);
}
return info;
}
@@ -346,21 +343,4 @@
Color.WHITE, WHITE_SCRIM_ALPHA);
return true;
}
-
- @Nullable
- static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
- Objects.requireNonNull(context);
- if (icon == null) return null;
- try {
- if (icon.getType() == Icon.TYPE_URI
- || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
- context.grantUriPermission(context.getPackageName(),
- icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- return icon.loadDrawable(context);
- } catch (Exception e) {
- Log.w(TAG, "loadSenderAvatar failed: " + e.getMessage());
- return null;
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 4d15605c..2128cbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -27,7 +27,7 @@
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 79c31e0..75adef4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -16,8 +16,8 @@
package com.android.wm.shell.dagger;
-import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS;
-import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS;
+import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
import android.annotation.Nullable;
import android.app.KeyguardManager;
@@ -71,10 +71,10 @@
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
import com.android.wm.shell.desktopmode.DesktopRepository;
+import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver;
-import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler;
@@ -92,9 +92,9 @@
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
-import com.android.wm.shell.freeform.TaskChangeListener;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarterInitializer;
+import com.android.wm.shell.freeform.TaskChangeListener;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.PipTransitionController;
@@ -111,6 +111,7 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.taskview.TaskViewTransitions;
import com.android.wm.shell.transition.DefaultMixedHandler;
+import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.HomeTransitionObserver;
import com.android.wm.shell.transition.MixedTransitionHandler;
import com.android.wm.shell.transition.Transitions;
@@ -391,10 +392,11 @@
Transitions transitions,
Optional<DesktopFullImmersiveTransitionHandler> desktopImmersiveTransitionHandler,
WindowDecorViewModel windowDecorViewModel,
- Optional<TaskChangeListener> taskChangeListener) {
+ Optional<TaskChangeListener> taskChangeListener,
+ FocusTransitionObserver focusTransitionObserver) {
return new FreeformTaskTransitionObserver(
context, shellInit, transitions, desktopImmersiveTransitionHandler,
- windowDecorViewModel, taskChangeListener);
+ windowDecorViewModel, taskChangeListener, focusTransitionObserver);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index 2b38cda..b8507e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -68,9 +68,7 @@
private val idSequence: InstanceIdSequence by lazy { InstanceIdSequence(Int.MAX_VALUE) }
init {
- if (
- Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.canEnterDesktopMode(context)
- ) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
shellInit.addInitCallback(this::onInit, this)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 7b2a5d3..c175133 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -80,6 +80,14 @@
freeformTasksInZOrder = ArrayList(freeformTasksInZOrder),
fullImmersiveTaskId = fullImmersiveTaskId
)
+ fun clear() {
+ activeTasks.clear()
+ visibleTasks.clear()
+ minimizedTasks.clear()
+ closingTasks.clear()
+ freeformTasksInZOrder.clear()
+ fullImmersiveTaskId = null
+ }
}
/* Current wallpaper activity token to remove wallpaper activity when last task is removed. */
@@ -414,6 +422,19 @@
}
/**
+ * Removes the desktop for the given [displayId] and returns the active tasks on that desktop.
+ */
+ fun removeDesktop(displayId: Int): ArraySet<Int> {
+ if (!desktopTaskDataByDisplayId.contains(displayId)) {
+ logW("Could not find desktop to remove: displayId=%d", displayId)
+ return ArraySet()
+ }
+ val activeTasks = ArraySet(desktopTaskDataByDisplayId[displayId].activeTasks)
+ desktopTaskDataByDisplayId[displayId].clear()
+ return activeTasks
+ }
+
+ /**
* Updates active desktop gesture exclusion regions.
*
* If [desktopExclusionRegions] is accepted by [desktopGestureExclusionListener], updates it in
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 5f41326..75c795b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.desktopmode
-import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityOptions
import android.app.KeyguardManager
import android.app.PendingIntent
@@ -44,9 +44,14 @@
import android.view.DragEvent
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_CLOSE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.window.DesktopModeFlags
+import android.window.DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE
+import android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
+import android.window.DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
import android.window.RemoteTransition
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
@@ -86,10 +91,6 @@
import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.shared.annotations.ExternalThread
import com.android.wm.shell.shared.annotations.ShellMainThread
-import android.window.flags.DesktopModeFlags
-import android.window.flags.DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE
-import android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
-import android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
@@ -261,17 +262,12 @@
val wct = WindowContainerTransaction()
bringDesktopAppsToFront(displayId, wct)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val transitionType = transitionType(remoteTransition)
- val handler =
- remoteTransition?.let {
- OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
- }
- transitions.startTransition(transitionType, wct, handler).also { t ->
- handler?.setTransition(t)
- }
- } else {
- shellTaskOrganizer.applyTransaction(wct)
+ val transitionType = transitionType(remoteTransition)
+ val handler = remoteTransition?.let {
+ OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
+ }
+ transitions.startTransition(transitionType, wct, handler).also { t ->
+ handler?.setTransition(t)
}
}
@@ -388,12 +384,8 @@
bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
addMoveToDesktopChanges(wct, task)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
- addPendingMinimizeTransition(transition, taskToMinimize)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
+ val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
+ addPendingMinimizeTransition(transition, taskToMinimize)
}
/**
@@ -499,11 +491,9 @@
// Rather than set windowing mode to multi-window at task level, set it to
// undefined and inherit from split stage.
wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
+
+ transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+
}
private fun exitSplitIfApplicable(wct: WindowContainerTransaction, taskInfo: RunningTaskInfo) {
@@ -537,17 +527,12 @@
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- exitDesktopTaskTransitionHandler.startTransition(
+ exitDesktopTaskTransitionHandler.startTransition(
transitionSource,
wct,
position,
mOnAnimationFinishedCallback
)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- releaseVisualIndicator()
- }
}
/** Move a task to the front */
@@ -584,12 +569,9 @@
wct.reorder(taskInfo.token, true /* onTop */, true /* includingParents */)
val taskToMinimize =
addAndGetMinimizeChangesIfNeeded(taskInfo.displayId, wct, taskInfo.taskId)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val transition = transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */)
- addPendingMinimizeTransition(transition, taskToMinimize)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
+
+ val transition = transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */)
+ addPendingMinimizeTransition(transition, taskToMinimize)
}
/**
@@ -645,11 +627,9 @@
val wct = WindowContainerTransaction()
wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
+
+ transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+
}
/** Moves a task in/out of full immersive state within the desktop. */
@@ -733,11 +713,9 @@
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding)
val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
+
+ toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
+
}
private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
@@ -847,11 +825,9 @@
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(true)
val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
- } else {
- shellTaskOrganizer.applyTransaction(wct)
- }
+
+ toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
+
}
@VisibleForTesting
@@ -1498,6 +1474,22 @@
}
}
+ fun removeDesktop(displayId: Int) {
+ if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return
+
+ val tasksToRemove = taskRepository.removeDesktop(displayId)
+ val wct = WindowContainerTransaction()
+ tasksToRemove.forEach {
+ val task = shellTaskOrganizer.getRunningTaskInfo(it)
+ if (task != null) {
+ wct.removeTask(task.token)
+ } else {
+ recentTasksController?.removeBackgroundTask(it)
+ }
+ }
+ if (!wct.isEmpty) transitions.startTransition(TRANSIT_CLOSE, wct, null)
+ }
+
/** Enter split by using the focused desktop task in given `displayId`. */
fun enterSplit(displayId: Int, leftOrTop: Boolean) {
getFocusedFreeformTask(displayId)?.let { requestSplit(it, leftOrTop) }
@@ -2025,6 +2017,12 @@
c.moveTaskToDesktop(taskId, transitionSource = transitionSource)
}
}
+
+ override fun removeDesktop(displayId: Int) {
+ executeRemoteCallWithTaskPermission(controller, "removeDesktop") { c ->
+ c.removeDesktop(displayId)
+ }
+ }
}
private fun logV(msg: String, vararg arguments: Any?) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index 37bec21..d6b7212 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -24,7 +24,7 @@
import android.view.WindowManager.TRANSIT_TO_BACK
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW
import com.android.internal.jank.InteractionJankMonitor
@@ -39,7 +39,7 @@
* Limits the number of tasks shown in Desktop Mode.
*
* This class should only be used if
- * [android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT]
+ * [android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT]
* is enabled and [maxTasksLimit] is strictly greater than 0.
*/
class DesktopTasksLimiter (
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index e086e40..a4bc2fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -24,8 +24,8 @@
import android.view.WindowManager.TRANSIT_TO_BACK
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
-import android.window.flags.DesktopModeFlags
-import android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
+import android.window.DesktopModeFlags
+import android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
@@ -48,9 +48,7 @@
) : Transitions.TransitionObserver {
init {
- if (
- Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.canEnterDesktopMode(context)
- ) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)) {
shellInit.addInitCallback(::onInit, this)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index b036e40e..1090a46 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -49,4 +49,7 @@
/** Move a task with given `taskId` to desktop */
void moveToDesktop(int taskId, in DesktopModeTransitionSource transitionSource);
+
+ /** Remove desktop on the given display */
+ void removeDesktop(int displayId);
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index fbd3c10..ae65892 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -24,7 +24,7 @@
import android.content.Context;
import android.util.SparseArray;
import android.view.SurfaceControl;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -99,11 +99,6 @@
state.mTaskInfo = taskInfo;
state.mLeash = leash;
mTasks.put(taskInfo.taskId, state);
- if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- mWindowDecorationViewModel.onTaskOpening(taskInfo, leash, t, t);
- t.apply();
- }
if (DesktopModeStatus.canEnterDesktopMode(mContext)) {
mDesktopRepository.ifPresent(repository -> {
@@ -139,9 +134,6 @@
});
}
mWindowDecorationViewModel.onTaskVanished(taskInfo);
- if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
- mWindowDecorationViewModel.destroyWindowDecoration(taskInfo);
- }
updateLaunchAdjacentController();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 056f6b9..4106a10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -30,6 +30,7 @@
import com.android.window.flags.Flags;
import com.android.wm.shell.desktopmode.DesktopFullImmersiveTransitionHandler;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -50,6 +51,7 @@
private final Optional<DesktopFullImmersiveTransitionHandler> mImmersiveTransitionHandler;
private final WindowDecorViewModel mWindowDecorViewModel;
private final Optional<TaskChangeListener> mTaskChangeListener;
+ private final FocusTransitionObserver mFocusTransitionObserver;
private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
new HashMap<>();
@@ -60,12 +62,14 @@
Transitions transitions,
Optional<DesktopFullImmersiveTransitionHandler> immersiveTransitionHandler,
WindowDecorViewModel windowDecorViewModel,
- Optional<TaskChangeListener> taskChangeListener) {
+ Optional<TaskChangeListener> taskChangeListener,
+ FocusTransitionObserver focusTransitionObserver) {
mTransitions = transitions;
mImmersiveTransitionHandler = immersiveTransitionHandler;
mWindowDecorViewModel = windowDecorViewModel;
mTaskChangeListener = taskChangeListener;
- if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) {
+ mFocusTransitionObserver = focusTransitionObserver;
+ if (FreeformComponents.isFreeformEnabled(context)) {
shellInit.addInitCallback(this::onInit, this);
}
}
@@ -87,6 +91,9 @@
// Otherwise window decoration relayout won't run with the immersive state up to date.
mImmersiveTransitionHandler.ifPresent(h -> h.onTransitionReady(transition));
}
+ // Update focus state first to ensure the correct state can be queried from listeners.
+ // TODO(371503964): Remove this once the unified task repository is ready.
+ mFocusTransitionObserver.updateFocusState(info);
final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index abec3b9..f8d2011 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -28,6 +28,8 @@
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
import static android.view.WindowManager.TRANSIT_SLEEP;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
@@ -44,6 +46,7 @@
import android.view.WindowManager;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.KeyguardState;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
@@ -388,5 +391,18 @@
mMainExecutor.execute(() ->
mIsLaunchingActivityOverLockscreen = isLaunchingActivityOverLockscreen);
}
+
+ @Override
+ public void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final KeyguardState keyguardState =
+ new KeyguardState.Builder(android.view.Display.DEFAULT_DISPLAY)
+ .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build();
+ wct.addKeyguardState(keyguardState);
+ mMainExecutor.execute(() -> {
+ mTransitions.startTransition(keyguardShowing ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK,
+ wct, KeyguardTransitionHandler.this);
+ });
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
index b7245b9..1d349e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitions.java
@@ -44,4 +44,11 @@
* Notify whether keyguard has created a remote animation runner for next app launch.
*/
default void setLaunchingActivityOverLockscreen(boolean isLaunchingActivityOverLockscreen) {}
+
+ /**
+ * Notifies Shell to start a keyguard transition directly.
+ * @param keyguardShowing whether keyguard is showing or not.
+ * @param aodShowing whether aod is showing or not.
+ */
+ default void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
new file mode 100644
index 0000000..f40a87c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.pip2.animation;
+
+import android.animation.Animator;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.shared.animation.Interpolators;
+
+/**
+ * Animator that handles bounds animations for entering PIP.
+ */
+public class PipEnterAnimator extends ValueAnimator
+ implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+ @NonNull private final SurfaceControl mLeash;
+ private final SurfaceControl.Transaction mStartTransaction;
+ private final SurfaceControl.Transaction mFinishTransaction;
+
+ // Bounds updated by the evaluator as animator is running.
+ private final Rect mAnimatedRect = new Rect();
+
+ private final RectEvaluator mRectEvaluator;
+ private final Rect mEndBounds = new Rect();
+ @Nullable private final Rect mSourceRectHint;
+ private final @Surface.Rotation int mRotation;
+ @Nullable private Runnable mAnimationStartCallback;
+ @Nullable private Runnable mAnimationEndCallback;
+
+ private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+ mSurfaceControlTransactionFactory;
+
+ // Internal state representing initial transform - cached to avoid recalculation.
+ private final PointF mInitScale = new PointF();
+ private final PointF mInitPos = new PointF();
+ private final Rect mInitCrop = new Rect();
+
+ public PipEnterAnimator(Context context,
+ @NonNull SurfaceControl leash,
+ SurfaceControl.Transaction startTransaction,
+ SurfaceControl.Transaction finishTransaction,
+ @NonNull Rect endBounds,
+ @Nullable Rect sourceRectHint,
+ @Surface.Rotation int rotation) {
+ mLeash = leash;
+ mStartTransaction = startTransaction;
+ mFinishTransaction = finishTransaction;
+ mRectEvaluator = new RectEvaluator(mAnimatedRect);
+ mEndBounds.set(endBounds);
+ mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
+ mRotation = rotation;
+ mSurfaceControlTransactionFactory =
+ new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
+
+ final int enterAnimationDuration = context.getResources()
+ .getInteger(R.integer.config_pipEnterAnimationDuration);
+ setDuration(enterAnimationDuration);
+ setFloatValues(0f, 1f);
+ setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ addListener(this);
+ addUpdateListener(this);
+ }
+
+ public void setAnimationStartCallback(@NonNull Runnable runnable) {
+ mAnimationStartCallback = runnable;
+ }
+
+ public void setAnimationEndCallback(@NonNull Runnable runnable) {
+ mAnimationEndCallback = runnable;
+ }
+
+ @Override
+ public void onAnimationStart(@NonNull Animator animation) {
+ if (mAnimationStartCallback != null) {
+ mAnimationStartCallback.run();
+ }
+ if (mStartTransaction != null) {
+ onEnterAnimationUpdate(mInitScale, mInitPos, mInitCrop,
+ 0f /* fraction */, mStartTransaction);
+ mStartTransaction.apply();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation) {
+ if (mAnimationEndCallback != null) {
+ mAnimationEndCallback.run();
+ }
+ }
+
+ @Override
+ public void onAnimationUpdate(@NonNull ValueAnimator animation) {
+ final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+ final float fraction = getAnimatedFraction();
+ onEnterAnimationUpdate(mInitScale, mInitPos, mInitCrop, fraction, tx);
+ tx.apply();
+ }
+
+ private void onEnterAnimationUpdate(PointF initScale, PointF initPos, Rect initCrop,
+ float fraction, SurfaceControl.Transaction tx) {
+ float scaleX = 1 + (initScale.x - 1) * (1 - fraction);
+ float scaleY = 1 + (initScale.y - 1) * (1 - fraction);
+ tx.setScale(mLeash, scaleX, scaleY);
+
+ float posX = initPos.x + (mEndBounds.left - initPos.x) * fraction;
+ float posY = initPos.y + (mEndBounds.top - initPos.y) * fraction;
+ tx.setPosition(mLeash, posX, posY);
+
+ Rect endCrop = new Rect(mEndBounds);
+ endCrop.offsetTo(0, 0);
+ mRectEvaluator.evaluate(fraction, initCrop, endCrop);
+ tx.setCrop(mLeash, mAnimatedRect);
+ }
+
+ // no-ops
+
+ @Override
+ public void onAnimationCancel(@NonNull Animator animation) {}
+
+ @Override
+ public void onAnimationRepeat(@NonNull Animator animation) {}
+
+ /**
+ * Caches the initial transform relevant values for the bounds enter animation.
+ *
+ * Since enter PiP makes use of a config-at-end transition, initial transform needs to be
+ * calculated differently from generic transitions.
+ * @param pipChange PiP change received as a transition target.
+ */
+ public void setEnterStartState(@NonNull TransitionInfo.Change pipChange) {
+ PipUtils.calcStartTransform(pipChange, mInitScale, mInitPos, mInitCrop);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipExpandAnimator.java
similarity index 77%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipExpandAnimator.java
index 8ebdc96..8fa5aa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipExpandAnimator.java
@@ -19,7 +19,6 @@
import android.animation.Animator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
-import android.annotation.IntDef;
import android.content.Context;
import android.graphics.Rect;
import android.view.Surface;
@@ -30,35 +29,22 @@
import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import com.android.wm.shell.shared.animation.Interpolators;
/**
- * Animator that handles bounds animations for entering / exiting PIP.
+ * Animator that handles bounds animations for exit-via-expanding PIP.
*/
-public class PipEnterExitAnimator extends ValueAnimator
+public class PipExpandAnimator extends ValueAnimator
implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
- @IntDef(prefix = {"BOUNDS_"}, value = {
- BOUNDS_ENTER,
- BOUNDS_EXIT
- })
-
- @Retention(RetentionPolicy.SOURCE)
- public @interface BOUNDS {}
-
- public static final int BOUNDS_ENTER = 0;
- public static final int BOUNDS_EXIT = 1;
-
- @NonNull private final SurfaceControl mLeash;
+ @NonNull
+ private final SurfaceControl mLeash;
private final SurfaceControl.Transaction mStartTransaction;
private final SurfaceControl.Transaction mFinishTransaction;
- private final int mEnterExitAnimationDuration;
- private final @BOUNDS int mDirection;
private final @Surface.Rotation int mRotation;
// optional callbacks for tracking animation start and end
- @Nullable private Runnable mAnimationStartCallback;
+ @Nullable
+ private Runnable mAnimationStartCallback;
@Nullable private Runnable mAnimationEndCallback;
private final Rect mBaseBounds = new Rect();
@@ -78,7 +64,7 @@
private final RectEvaluator mInsetEvaluator;
private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
- public PipEnterExitAnimator(Context context,
+ public PipExpandAnimator(Context context,
@NonNull SurfaceControl leash,
SurfaceControl.Transaction startTransaction,
SurfaceControl.Transaction finishTransaction,
@@ -86,7 +72,6 @@
@NonNull Rect startBounds,
@NonNull Rect endBounds,
@Nullable Rect sourceRectHint,
- @BOUNDS int direction,
@Surface.Rotation int rotation) {
mLeash = leash;
mStartTransaction = startTransaction;
@@ -98,7 +83,6 @@
mRectEvaluator = new RectEvaluator(mAnimatedRect);
mInsetEvaluator = new RectEvaluator(new Rect());
mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context);
- mDirection = direction;
mRotation = rotation;
mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
@@ -113,12 +97,14 @@
mSurfaceControlTransactionFactory =
new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
- mEnterExitAnimationDuration = context.getResources()
+
+ final int enterAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipEnterAnimationDuration);
+ setDuration(enterAnimationDuration);
setObjectValues(startBounds, endBounds);
- setDuration(mEnterExitAnimationDuration);
setEvaluator(mRectEvaluator);
+ setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
addListener(this);
addUpdateListener(this);
}
@@ -147,9 +133,10 @@
// finishTransaction might override some state (eg. corner radii) so we want to
// manually set the state to the end of the animation
mPipSurfaceTransactionHelper.scaleAndCrop(mFinishTransaction, mLeash, mSourceRectHint,
- mBaseBounds, mAnimatedRect, getInsets(1f), isInPipDirection(), 1f)
- .round(mFinishTransaction, mLeash, isInPipDirection())
- .shadow(mFinishTransaction, mLeash, isInPipDirection());
+ mBaseBounds, mAnimatedRect, getInsets(1f),
+ false /* isInPipDirection */, 1f)
+ .round(mFinishTransaction, mLeash, false /* applyCornerRadius */)
+ .shadow(mFinishTransaction, mLeash, false /* applyCornerRadius */);
}
if (mAnimationEndCallback != null) {
mAnimationEndCallback.run();
@@ -160,32 +147,22 @@
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
final float fraction = getAnimatedFraction();
- Rect insets = getInsets(fraction);
// TODO (b/350801661): implement fixed rotation
+ Rect insets = getInsets(fraction);
mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint,
- mBaseBounds, mAnimatedRect, insets, isInPipDirection(), fraction)
- .round(tx, mLeash, isInPipDirection())
- .shadow(tx, mLeash, isInPipDirection());
+ mBaseBounds, mAnimatedRect, insets, false /* isInPipDirection */, fraction)
+ .round(tx, mLeash, false /* applyCornerRadius */)
+ .shadow(tx, mLeash, false /* applyCornerRadius */);
tx.apply();
}
-
private Rect getInsets(float fraction) {
- Rect startInsets = isInPipDirection() ? mZeroInsets : mSourceRectHintInsets;
- Rect endInsets = isInPipDirection() ? mSourceRectHintInsets : mZeroInsets;
-
+ final Rect startInsets = mSourceRectHintInsets;
+ final Rect endInsets = mZeroInsets;
return mInsetEvaluator.evaluate(fraction, startInsets, endInsets);
}
- private boolean isInPipDirection() {
- return mDirection == BOUNDS_ENTER;
- }
-
- private boolean isOutPipDirection() {
- return mDirection == BOUNDS_EXIT;
- }
-
// no-ops
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 62a60fa..b57f51a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -56,7 +56,8 @@
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
-import com.android.wm.shell.pip2.animation.PipEnterExitAnimator;
+import com.android.wm.shell.pip2.animation.PipEnterAnimator;
+import com.android.wm.shell.pip2.animation.PipExpandAnimator;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.pip.PipContentOverlay;
import com.android.wm.shell.sysui.ShellInit;
@@ -218,6 +219,7 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
+ mFinishCallback = finishCallback;
if (transition == mEnterTransition || info.getType() == TRANSIT_PIP) {
mEnterTransition = null;
// If we are in swipe PiP to Home transition we are ENTERING_PIP as a jumpcut transition
@@ -258,6 +260,7 @@
if (isRemovePipTransition(info)) {
return removePipImmediately(info, startTransaction, finishTransaction, finishCallback);
}
+ mFinishCallback = null;
return false;
}
@@ -297,7 +300,6 @@
mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
}
- mFinishCallback = finishCallback;
mPipTransitionState.setState(PipTransitionState.CHANGING_PIP_BOUNDS, extra);
return true;
}
@@ -349,7 +351,6 @@
startTransaction.setMatrix(pipLeash, transformTensor, matrixTmp);
}
startTransaction.apply();
- finishCallback.onTransitionFinished(null /* finishWct */);
finishInner();
return true;
}
@@ -386,14 +387,6 @@
return false;
}
- WindowContainerToken pipTaskToken = pipChange.getContainer();
- if (pipTaskToken == null) {
- return false;
- }
-
- WindowContainerTransaction finishWct = new WindowContainerTransaction();
- SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-
Rect startBounds = pipChange.getStartAbsBounds();
Rect endBounds = pipChange.getEndAbsBounds();
SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash;
@@ -405,29 +398,22 @@
sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
}
- // For opening type transitions, if there is a non-pip change of mode TO_FRONT/OPEN,
+ // For opening type transitions, if there is a change of mode TO_FRONT/OPEN,
// make sure that change has alpha of 1f, since it's init state might be set to alpha=0f
// by the Transitions framework to simplify Task opening transitions.
if (TransitionUtil.isOpeningType(info.getType())) {
for (TransitionInfo.Change change : info.getChanges()) {
- if (change.getLeash() == null || change == pipChange) continue;
+ if (change.getLeash() == null) continue;
if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
startTransaction.setAlpha(change.getLeash(), 1f);
}
}
}
- PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash,
- startTransaction, finishTransaction, startBounds, startBounds, endBounds,
- sourceRectHint, PipEnterExitAnimator.BOUNDS_ENTER, Surface.ROTATION_0);
-
- tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
- this::finishInner);
- finishWct.setBoundsChangeTransaction(pipTaskToken, tx);
-
- animator.setAnimationEndCallback(() ->
- finishCallback.onTransitionFinished(finishWct));
-
+ PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
+ startTransaction, finishTransaction, endBounds, sourceRectHint, Surface.ROTATION_0);
+ animator.setAnimationStartCallback(() -> animator.setEnterStartState(pipChange));
+ animator.setAnimationEndCallback(this::finishInner);
animator.start();
return true;
}
@@ -452,11 +438,8 @@
PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction,
PipAlphaAnimator.FADE_IN);
- animator.setAnimationEndCallback(() -> {
- finishCallback.onTransitionFinished(null);
- // This should update the pip transition state accordingly after we stop playing.
- finishInner();
- });
+ // This should update the pip transition state accordingly after we stop playing.
+ animator.setAnimationEndCallback(this::finishInner);
animator.start();
return true;
@@ -510,9 +493,9 @@
sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint();
}
- PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash,
+ PipExpandAnimator animator = new PipExpandAnimator(mContext, pipLeash,
startTransaction, finishTransaction, endBounds, startBounds, endBounds,
- sourceRectHint, PipEnterExitAnimator.BOUNDS_EXIT, Surface.ROTATION_0);
+ sourceRectHint, Surface.ROTATION_0);
animator.setAnimationEndCallback(() -> {
mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
@@ -631,6 +614,7 @@
//
private void finishInner() {
+ finishTransition(null /* tx */);
if (mPipTransitionState.getSwipePipToHomeOverlay() != null) {
startOverlayFadeoutAnimation();
} else if (mPipTransitionState.getState() == PipTransitionState.ENTERING_PIP) {
@@ -652,6 +636,7 @@
}
if (mFinishCallback != null) {
mFinishCallback.onTransitionFinished(wct);
+ mFinishCallback = null;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 95cb3df..6086801 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -38,8 +38,8 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.window.DesktopModeFlags;
import android.window.WindowContainerToken;
-import android.window.flags.DesktopModeFlags;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -540,6 +540,14 @@
return null;
}
+ /**
+ * Remove the background task that match the given taskId. This will remove the task regardless
+ * of whether it's active or recent.
+ */
+ public boolean removeBackgroundTask(int taskId) {
+ return mActivityTaskManager.removeTask(taskId);
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
index f2c08dc..1af99f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -21,7 +21,7 @@
import android.util.ArrayMap
import android.view.SurfaceControl
import android.window.TransitionInfo
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
@@ -42,9 +42,7 @@
ArrayMap<TaskStackTransitionObserverListener, Executor>()
init {
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- shellInit.addInitCallback(::onInit, this)
- }
+ shellInit.addInitCallback(::onInit, this)
}
fun onInit() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
index 399e39a..6d01e24 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java
@@ -16,7 +16,8 @@
package com.android.wm.shell.transition;
-import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
@@ -24,10 +25,11 @@
import static com.android.wm.shell.transition.Transitions.TransitionObserver;
import android.annotation.NonNull;
-import android.os.IBinder;
+import android.app.ActivityManager.RunningTaskInfo;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
-import android.view.SurfaceControl;
+import android.util.SparseArray;
import android.window.TransitionInfo;
import com.android.wm.shell.shared.FocusTransitionListener;
@@ -43,44 +45,64 @@
* It reports transitions to callers outside of the process via {@link IFocusTransitionListener},
* and callers within the process via {@link FocusTransitionListener}.
*/
-public class FocusTransitionObserver implements TransitionObserver {
+public class FocusTransitionObserver {
private static final String TAG = FocusTransitionObserver.class.getSimpleName();
private IFocusTransitionListener mRemoteListener;
private final Map<FocusTransitionListener, Executor> mLocalListeners =
new HashMap<>();
- private int mFocusedDisplayId = INVALID_DISPLAY;
+ private int mFocusedDisplayId = DEFAULT_DISPLAY;
+ private final SparseArray<RunningTaskInfo> mFocusedTaskOnDisplay = new SparseArray<>();
+
+ private final ArraySet<RunningTaskInfo> mTmpTasksToBeNotified = new ArraySet<>();
public FocusTransitionObserver() {}
- @Override
- public void onTransitionReady(@NonNull IBinder transition,
- @NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction startTransaction,
- @NonNull SurfaceControl.Transaction finishTransaction) {
+ /**
+ * Update display/window focus state from the given transition info and notifies changes if any.
+ */
+ public void updateFocusState(@NonNull TransitionInfo info) {
+ if (!enableDisplayFocusInShellTransitions()) {
+ return;
+ }
final List<TransitionInfo.Change> changes = info.getChanges();
for (int i = changes.size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = changes.get(i);
+
+ final RunningTaskInfo task = change.getTaskInfo();
+ if (task != null
+ && (change.hasFlags(FLAG_MOVED_TO_TOP) || change.getMode() == TRANSIT_OPEN)) {
+ final RunningTaskInfo lastFocusedTaskOnDisplay =
+ mFocusedTaskOnDisplay.get(task.displayId);
+ if (lastFocusedTaskOnDisplay != null) {
+ mTmpTasksToBeNotified.add(lastFocusedTaskOnDisplay);
+ }
+ mTmpTasksToBeNotified.add(task);
+ mFocusedTaskOnDisplay.put(task.displayId, task);
+ }
+
if (change.hasFlags(FLAG_IS_DISPLAY) && change.hasFlags(FLAG_MOVED_TO_TOP)) {
if (mFocusedDisplayId != change.getEndDisplayId()) {
+ final RunningTaskInfo lastGloballyFocusedTask =
+ mFocusedTaskOnDisplay.get(mFocusedDisplayId);
+ if (lastGloballyFocusedTask != null) {
+ mTmpTasksToBeNotified.add(lastGloballyFocusedTask);
+ }
mFocusedDisplayId = change.getEndDisplayId();
notifyFocusedDisplayChanged();
+ final RunningTaskInfo currentGloballyFocusedTask =
+ mFocusedTaskOnDisplay.get(mFocusedDisplayId);
+ if (currentGloballyFocusedTask != null) {
+ mTmpTasksToBeNotified.add(currentGloballyFocusedTask);
+ }
}
- return;
}
}
+ mTmpTasksToBeNotified.forEach(this::notifyTaskFocusChanged);
+ mTmpTasksToBeNotified.clear();
}
- @Override
- public void onTransitionStarting(@NonNull IBinder transition) {}
-
- @Override
- public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {}
-
- @Override
- public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {}
-
/**
* Sets the focus transition listener that receives any transitions resulting in focus switch.
* This is for calls from outside the Shell, within the host process.
@@ -92,7 +114,10 @@
return;
}
mLocalListeners.put(listener, executor);
- executor.execute(() -> listener.onFocusedDisplayChanged(mFocusedDisplayId));
+ executor.execute(() -> {
+ listener.onFocusedDisplayChanged(mFocusedDisplayId);
+ mTmpTasksToBeNotified.forEach(this::notifyTaskFocusChanged);
+ });
}
/**
@@ -120,13 +145,20 @@
notifyFocusedDisplayChangedToRemote();
}
- /**
- * Notifies the listener that display focus has changed.
- */
- public void notifyFocusedDisplayChanged() {
+ private void notifyTaskFocusChanged(RunningTaskInfo task) {
+ final boolean isFocusedOnDisplay = isFocusedOnDisplay(task);
+ final boolean isFocusedGlobally = hasGlobalFocus(task);
+ mLocalListeners.forEach((listener, executor) ->
+ executor.execute(() -> listener.onFocusedTaskChanged(task.taskId,
+ isFocusedOnDisplay, isFocusedGlobally)));
+ }
+
+ private void notifyFocusedDisplayChanged() {
notifyFocusedDisplayChangedToRemote();
mLocalListeners.forEach((listener, executor) ->
- executor.execute(() -> listener.onFocusedDisplayChanged(mFocusedDisplayId)));
+ executor.execute(() -> {
+ listener.onFocusedDisplayChanged(mFocusedDisplayId);
+ }));
}
private void notifyFocusedDisplayChangedToRemote() {
@@ -138,4 +170,23 @@
}
}
}
+
+ private boolean isFocusedOnDisplay(@NonNull RunningTaskInfo task) {
+ if (!enableDisplayFocusInShellTransitions()) {
+ return task.isFocused;
+ }
+ final RunningTaskInfo focusedTaskOnDisplay = mFocusedTaskOnDisplay.get(task.displayId);
+ return focusedTaskOnDisplay != null && focusedTaskOnDisplay.taskId == task.taskId;
+ }
+
+ /**
+ * Checks whether the given task has focused globally on the system.
+ * (Note {@link RunningTaskInfo#isFocused} represents per-display focus.)
+ */
+ public boolean hasGlobalFocus(@NonNull RunningTaskInfo task) {
+ if (!enableDisplayFocusInShellTransitions()) {
+ return task.isFocused;
+ }
+ return task.displayId == mFocusedDisplayId && isFocusedOnDisplay(task);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index d5e92e6..346f21b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -392,8 +392,6 @@
mShellCommandHandler.addCommandCallback("transitions", this, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
-
- registerObserver(mFocusTransitionObserver);
}
public boolean isRegistered() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 839973f..576c911 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -16,7 +16,7 @@
package com.android.wm.shell.windowdecor;
-import static android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING;
+import static android.window.DesktopModeFlags.ENABLE_WINDOWING_SCALED_RESIZING;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index bcf48d9..e55bc67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -77,10 +77,10 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Toast;
+import android.window.DesktopModeFlags;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.flags.DesktopModeFlags;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
@@ -103,8 +103,8 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler;
-import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator;
+import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
@@ -133,14 +133,14 @@
import kotlin.Pair;
import kotlin.Unit;
-import kotlinx.coroutines.ExperimentalCoroutinesApi;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
/**
* View model for the window decoration with a caption and shadows. Works with
* {@link DesktopModeWindowDecoration}.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 25d37fc..a78fb9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -24,8 +24,8 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
@@ -72,9 +72,9 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.ImageButton;
+import android.window.DesktopModeFlags;
import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;
-import android.window.flags.DesktopModeFlags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index 38f9cfa..60c9222 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -27,7 +27,7 @@
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
import androidx.annotation.NonNull;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index d726f50..33d1c26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -18,7 +18,7 @@
import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
-import static android.window.flags.DesktopModeFlags.ENABLE_WINDOWING_EDGE_DRAG_RESIZE;
+import static android.window.DesktopModeFlags.ENABLE_WINDOWING_EDGE_DRAG_RESIZE;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
index 68a58ee0..376cd2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -33,7 +33,7 @@
import androidx.core.animation.doOnStart
import androidx.core.content.ContextCompat
import com.android.wm.shell.R
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
private const val MAX_DRAWABLE_ALPHA = 255
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index 52bf400..c2af1d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -49,7 +49,7 @@
import com.android.window.flags.Flags
import com.android.window.flags.Flags.enableMinimizeButton
import com.android.wm.shell.R
-import android.window.flags.DesktopModeFlags
+import android.window.DesktopModeFlags
import com.android.wm.shell.windowdecor.MaximizeButtonView
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.OPACITY_100
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 58559ac..7b6cfe3 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -30,7 +30,6 @@
java_library {
name: "wm-shell-flicker-utils",
- platform_apis: true,
optimize: {
enabled: false,
},
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index db65ae1..daf7e7d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -110,16 +110,11 @@
shellInit = spy(ShellInit(testExecutor))
desktopModeEventLogger = mock<DesktopModeEventLogger>()
- transitionObserver =
- DesktopModeLoggerTransitionObserver(
- context, mockShellInit, transitions, desktopModeEventLogger)
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
- verify(mockShellInit).addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
- initRunnableCaptor.value.run()
- } else {
- transitionObserver.onInit()
- }
+ transitionObserver = DesktopModeLoggerTransitionObserver(
+ context, mockShellInit, transitions, desktopModeEventLogger)
+ val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+ verify(mockShellInit).addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+ initRunnableCaptor.value.run()
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 55b9724..1308114 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -940,6 +940,23 @@
assertThat(repo.isTaskInFullImmersiveState(taskId = 2)).isTrue()
}
+ @Test
+ fun removeDesktop_multipleTasks_removesAll() {
+ repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 1)
+ repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 2)
+ repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 3)
+ // The front-most task will be the one added last through `addOrMoveFreeformTaskToTop`
+ repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 3)
+ repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 2)
+ repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 1)
+ repo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = 2)
+
+ val tasksBeforeRemoval = repo.removeDesktop(displayId = DEFAULT_DISPLAY)
+
+ assertThat(tasksBeforeRemoval).containsExactly(1, 2, 3).inOrder()
+ assertThat(repo.getActiveTasks(displayId = DEFAULT_DISPLAY)).isEmpty()
+ }
+
class TestListener : DesktopRepository.ActiveTasksListener {
var activeChangesOnDefaultDisplay = 0
var activeChangesOnSecondaryDisplay = 0
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index ae4772e..27deb0b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -2466,6 +2466,41 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+ fun removeDesktop_multipleTasks_removesAll() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+ taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
+
+ controller.removeDesktop(displayId = DEFAULT_DISPLAY)
+
+ val wct = getLatestWct(TRANSIT_CLOSE)
+ assertThat(wct.hierarchyOps).hasSize(3)
+ wct.assertRemoveAt(index = 0, task1.token)
+ wct.assertRemoveAt(index = 1, task2.token)
+ wct.assertRemoveAt(index = 2, task3.token)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
+ fun removeDesktop_multipleTasksWithBackgroundTask_removesAll() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val task3 = setUpFreeformTask()
+ taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
+ whenever(shellTaskOrganizer.getRunningTaskInfo(task3.taskId)).thenReturn(null)
+
+ controller.removeDesktop(displayId = DEFAULT_DISPLAY)
+
+ val wct = getLatestWct(TRANSIT_CLOSE)
+ assertThat(wct.hierarchyOps).hasSize(2)
+ wct.assertRemoveAt(index = 0, task1.token)
+ wct.assertRemoveAt(index = 1, task2.token)
+ verify(recentTasksController).removeBackgroundTask(task3.taskId)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
fun dragToDesktop_landscapeDevice_resizable_undefinedOrientation_defaultLandscapeBounds() {
val spyController = spy(controller)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
index da95315..145819f3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
@@ -22,7 +22,6 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_CHANGE;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -44,18 +43,14 @@
import androidx.test.filters.SmallTest;
import com.android.window.flags.Flags;
-
-import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
import com.android.wm.shell.desktopmode.DesktopFullImmersiveTransitionHandler;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.TransitionInfoBuilder;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
-import java.util.Optional;
-
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -80,6 +75,9 @@
private WindowDecorViewModel mWindowDecorViewModel;
@Mock
private TaskChangeListener mTaskChangeListener;
+ @Mock
+ private FocusTransitionObserver mFocusTransitionObserver;
+
private FreeformTaskTransitionObserver mTransitionObserver;
@Before
@@ -95,16 +93,13 @@
mTransitionObserver = new FreeformTaskTransitionObserver(
context, mShellInit, mTransitions,
Optional.of(mDesktopFullImmersiveTransitionHandler),
- mWindowDecorViewModel, Optional.of(mTaskChangeListener));
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
- Runnable.class);
- verify(mShellInit).addInitCallback(initRunnableCaptor.capture(),
- same(mTransitionObserver));
- initRunnableCaptor.getValue().run();
- } else {
- mTransitionObserver.onInit();
- }
+ mWindowDecorViewModel, Optional.of(mTaskChangeListener), mFocusTransitionObserver);
+
+ final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
+ Runnable.class);
+ verify(mShellInit).addInitCallback(initRunnableCaptor.capture(),
+ same(mTransitionObserver));
+ initRunnableCaptor.getValue().run();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
index d63158c..015ea20 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java
@@ -23,6 +23,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -30,9 +31,6 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager.RunningTaskInfo;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -43,17 +41,11 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import com.android.window.flags.Flags;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.shared.IFocusTransitionListener;
-import com.android.wm.shell.shared.TransactionPool;
-import com.android.wm.shell.sysui.ShellController;
-import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.shared.FocusTransitionListener;
import org.junit.Before;
import org.junit.Rule;
@@ -75,57 +67,64 @@
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
- private IFocusTransitionListener mListener;
- private Transitions mTransition;
+ private FocusTransitionListener mListener;
+ private final TestShellExecutor mShellExecutor = new TestShellExecutor();
private FocusTransitionObserver mFocusTransitionObserver;
@Before
public void setUp() {
- mListener = mock(IFocusTransitionListener.class);
- when(mListener.asBinder()).thenReturn(mock(IBinder.class));
-
+ mListener = mock(FocusTransitionListener.class);
mFocusTransitionObserver = new FocusTransitionObserver();
- mTransition =
- new Transitions(InstrumentationRegistry.getInstrumentation().getTargetContext(),
- mock(ShellInit.class), mock(ShellController.class),
- mock(ShellTaskOrganizer.class), mock(TransactionPool.class),
- mock(DisplayController.class), new TestShellExecutor(),
- new Handler(Looper.getMainLooper()), new TestShellExecutor(),
- mock(HomeTransitionObserver.class),
- mFocusTransitionObserver);
- mFocusTransitionObserver.setRemoteFocusTransitionListener(mTransition, mListener);
+ mFocusTransitionObserver.setLocalFocusTransitionListener(mListener, mShellExecutor);
+ mShellExecutor.flushAll();
+ clearInvocations(mListener);
}
@Test
- public void testOnlyDisplayChangeAffectsDisplayFocus() throws RemoteException {
- final IBinder binder = mock(IBinder.class);
+ public void testBasicTaskAndDisplayFocusSwitch() throws RemoteException {
final SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
- // Open a task on the secondary display, but it doesn't change display focus because it only
- // has a task change.
+ // First, open a task on the default display.
TransitionInfo info = mock(TransitionInfo.class);
final List<TransitionInfo.Change> changes = new ArrayList<>();
- setupTaskChange(changes, 123 /* taskId */, TRANSIT_OPEN, SECONDARY_DISPLAY_ID,
- true /* focused */);
+ setupTaskChange(changes, 1 /* taskId */, TRANSIT_OPEN,
+ DEFAULT_DISPLAY, true /* focused */);
when(info.getChanges()).thenReturn(changes);
- mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx);
- verify(mListener, never()).onFocusedDisplayChanged(SECONDARY_DISPLAY_ID);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, never()).onFocusedDisplayChanged(anyInt());
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
clearInvocations(mListener);
- // Moving the secondary display to front must change display focus to it.
- changes.clear();
+ // Open a task on the secondary display.
+ setupTaskChange(changes, 2 /* taskId */, TRANSIT_OPEN,
+ SECONDARY_DISPLAY_ID, true /* focused */);
setupDisplayToTopChange(changes, SECONDARY_DISPLAY_ID);
when(info.getChanges()).thenReturn(changes);
- mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
verify(mListener, times(1))
.onFocusedDisplayChanged(SECONDARY_DISPLAY_ID);
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ clearInvocations(mListener);
- // Moving the secondary display to front must change display focus back to it.
+ // Moving only the default display back to front, and verify that affected tasks are also
+ // notified.
changes.clear();
setupDisplayToTopChange(changes, DEFAULT_DISPLAY);
when(info.getChanges()).thenReturn(changes);
- mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx);
- verify(mListener, times(1)).onFocusedDisplayChanged(DEFAULT_DISPLAY);
+ mFocusTransitionObserver.updateFocusState(info);
+ mShellExecutor.flushAll();
+ verify(mListener, times(1))
+ .onFocusedDisplayChanged(DEFAULT_DISPLAY);
+ verify(mListener, times(1)).onFocusedTaskChanged(1 /* taskId */,
+ true /* isFocusedOnDisplay */, true /* isFocusedGlobally */);
+ verify(mListener, times(1)).onFocusedTaskChanged(2 /* taskId */,
+ true /* isFocusedOnDisplay */, false /* isFocusedGlobally */);
}
private void setupTaskChange(List<TransitionInfo.Change> changes, int taskId,
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index f066e46..3ecd82b 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -65,13 +65,7 @@
uint32_t string_pool_index_offset;
};
-struct Idmap_target_entry {
- uint32_t target_id;
- uint32_t overlay_id;
-};
-
struct Idmap_target_entry_inline {
- uint32_t target_id;
uint32_t start_value_index;
uint32_t value_count;
};
@@ -81,10 +75,9 @@
Res_value value;
};
-struct Idmap_overlay_entry {
- uint32_t overlay_id;
- uint32_t target_id;
-};
+static constexpr uint32_t convert_dev_target_id(uint32_t dev_target_id) {
+ return (0x00FFFFFFU & dtohl(dev_target_id));
+}
OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap)
: data_header_(loaded_idmap->data_header_),
@@ -117,27 +110,29 @@
}
OverlayDynamicRefTable::OverlayDynamicRefTable(const Idmap_data_header* data_header,
- const Idmap_overlay_entry* entries,
+ Idmap_overlay_entries entries,
uint8_t target_assigned_package_id)
: data_header_(data_header),
entries_(entries),
- target_assigned_package_id_(target_assigned_package_id) {}
+ target_assigned_package_id_(target_assigned_package_id) {
+}
status_t OverlayDynamicRefTable::lookupResourceId(uint32_t* resId) const {
- const Idmap_overlay_entry* first_entry = entries_;
- const Idmap_overlay_entry* end_entry = entries_ + dtohl(data_header_->overlay_entry_count);
- auto entry = std::lower_bound(first_entry, end_entry, *resId,
- [](const Idmap_overlay_entry& e1, const uint32_t overlay_id) {
- return dtohl(e1.overlay_id) < overlay_id;
- });
+ const auto count = dtohl(data_header_->overlay_entry_count);
+ const auto overlay_it_end = entries_.overlay_id + count;
+ const auto entry_it = std::lower_bound(entries_.overlay_id, overlay_it_end, *resId,
+ [](uint32_t dev_overlay_id, uint32_t overlay_id) {
+ return dtohl(dev_overlay_id) < overlay_id;
+ });
- if (entry == end_entry || dtohl(entry->overlay_id) != *resId) {
+ if (entry_it == overlay_it_end || dtohl(*entry_it) != *resId) {
// A mapping for the target resource id could not be found.
return DynamicRefTable::lookupResourceId(resId);
}
- *resId = (0x00FFFFFFU & dtohl(entry->target_id))
- | (((uint32_t) target_assigned_package_id_) << 24U);
+ const auto index = entry_it - entries_.overlay_id;
+ *resId = convert_dev_target_id(entries_.target_id[index]) |
+ (((uint32_t)target_assigned_package_id_) << 24U);
return NO_ERROR;
}
@@ -145,12 +140,10 @@
return DynamicRefTable::lookupResourceId(resId);
}
-IdmapResMap::IdmapResMap(const Idmap_data_header* data_header,
- const Idmap_target_entry* entries,
- const Idmap_target_entry_inline* inline_entries,
+IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
+ Idmap_target_inline_entries inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
- const ConfigDescription* configs,
- uint8_t target_assigned_package_id,
+ const ConfigDescription* configs, uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table)
: data_header_(data_header),
entries_(entries),
@@ -158,7 +151,8 @@
inline_entry_values_(inline_entry_values),
configurations_(configs),
target_assigned_package_id_(target_assigned_package_id),
- overlay_ref_table_(overlay_ref_table) { }
+ overlay_ref_table_(overlay_ref_table) {
+}
IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
if ((target_res_id >> 24U) != target_assigned_package_id_) {
@@ -171,15 +165,15 @@
target_res_id &= 0x00FFFFFFU;
// Check if the target resource is mapped to an overlay resource.
- auto first_entry = entries_;
- auto end_entry = entries_ + dtohl(data_header_->target_entry_count);
- auto entry = std::lower_bound(first_entry, end_entry, target_res_id,
- [](const Idmap_target_entry& e, const uint32_t target_id) {
- return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
- });
+ const auto target_end = entries_.target_id + dtohl(data_header_->target_entry_count);
+ auto target_it = std::lower_bound(entries_.target_id, target_end, target_res_id,
+ [](uint32_t dev_target_id, uint32_t target_id) {
+ return convert_dev_target_id(dev_target_id) < target_id;
+ });
- if (entry != end_entry && (0x00FFFFFFU & dtohl(entry->target_id)) == target_res_id) {
- uint32_t overlay_resource_id = dtohl(entry->overlay_id);
+ if (target_it != target_end && convert_dev_target_id(*target_it) == target_res_id) {
+ const auto index = target_it - entries_.target_id;
+ uint32_t overlay_resource_id = dtohl(entries_.overlay_id[index]);
// Lookup the resource without rewriting the overlay resource id back to the target resource id
// being looked up.
overlay_ref_table_->lookupResourceIdNoRewrite(&overlay_resource_id);
@@ -187,20 +181,22 @@
}
// Check if the target resources is mapped to an inline table entry.
- auto first_inline_entry = inline_entries_;
- auto end_inline_entry = inline_entries_ + dtohl(data_header_->target_inline_entry_count);
- auto inline_entry = std::lower_bound(first_inline_entry, end_inline_entry, target_res_id,
- [](const Idmap_target_entry_inline& e,
- const uint32_t target_id) {
- return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
- });
+ const auto inline_entry_target_end =
+ inline_entries_.target_id + dtohl(data_header_->target_inline_entry_count);
+ const auto inline_entry_target_it =
+ std::lower_bound(inline_entries_.target_id, inline_entry_target_end, target_res_id,
+ [](uint32_t dev_target_id, uint32_t target_id) {
+ return convert_dev_target_id(dev_target_id) < target_id;
+ });
- if (inline_entry != end_inline_entry &&
- (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) {
+ if (inline_entry_target_it != inline_entry_target_end &&
+ convert_dev_target_id(*inline_entry_target_it) == target_res_id) {
+ const auto index = inline_entry_target_it - inline_entries_.target_id;
std::map<ConfigDescription, Res_value> values_map;
- for (int i = 0; i < inline_entry->value_count; i++) {
- const auto& value = inline_entry_values_[inline_entry->start_value_index + i];
- const auto& config = configurations_[value.config_index];
+ const auto& inline_entry = inline_entries_.entry[index];
+ for (int i = 0; i < dtohl(inline_entry.value_count); i++) {
+ const auto& value = inline_entry_values_[dtohl(inline_entry.start_value_index) + i];
+ const auto& config = configurations_[dtohl(value.config_index)];
values_map[config] = value.value;
}
return Result(std::move(values_map));
@@ -210,15 +206,15 @@
namespace {
template <typename T>
-const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const std::string& label,
+const T* ReadType(const uint8_t** in_out_data_ptr, size_t* in_out_size, const char* label,
size_t count = 1) {
if (!util::IsFourByteAligned(*in_out_data_ptr)) {
- LOG(ERROR) << "Idmap " << label << " is not word aligned.";
+ LOG(ERROR) << "Idmap " << label << " in " << __func__ << " is not word aligned.";
return {};
}
if ((*in_out_size / sizeof(T)) < count) {
- LOG(ERROR) << "Idmap too small for the number of " << label << " entries ("
- << count << ").";
+ LOG(ERROR) << "Idmap too small for the number of " << label << " in " << __func__
+ << " entries (" << count << ").";
return nullptr;
}
auto data_ptr = *in_out_data_ptr;
@@ -229,8 +225,8 @@
}
std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size_t* in_out_size,
- const std::string& label) {
- const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label + " length");
+ const char* label) {
+ const auto* len = ReadType<uint32_t>(in_out_data_ptr, in_out_size, label);
if (len == nullptr) {
return {};
}
@@ -242,7 +238,7 @@
const uint32_t padding_size = (4U - ((size_t)*in_out_data_ptr & 0x3U)) % 4U;
for (uint32_t i = 0; i < padding_size; i++) {
if (**in_out_data_ptr != 0) {
- LOG(ERROR) << " Idmap padding of " << label << " is non-zero.";
+ LOG(ERROR) << " Idmap padding of " << label << " in " << __func__ << " is non-zero.";
return {};
}
*in_out_data_ptr += sizeof(uint8_t);
@@ -258,12 +254,10 @@
#endif
LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
- const Idmap_data_header* data_header,
- const Idmap_target_entry* target_entries,
- const Idmap_target_entry_inline* target_inline_entries,
+ const Idmap_data_header* data_header, Idmap_target_entries target_entries,
+ Idmap_target_inline_entries target_inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
- const ConfigDescription* configs,
- const Idmap_overlay_entry* overlay_entries,
+ const ConfigDescription* configs, Idmap_overlay_entries overlay_entries,
std::unique_ptr<ResStringPool>&& string_pool,
std::string_view overlay_apk_path, std::string_view target_apk_path)
: header_(header),
@@ -274,10 +268,12 @@
configurations_(configs),
overlay_entries_(overlay_entries),
string_pool_(std::move(string_pool)),
- idmap_fd_(android::base::utf8::open(idmap_path.c_str(), O_RDONLY|O_CLOEXEC|O_BINARY|O_PATH)),
+ idmap_fd_(
+ android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)),
overlay_apk_path_(overlay_apk_path),
target_apk_path_(target_apk_path),
- idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {}
+ idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {
+}
std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) {
ATRACE_CALL();
@@ -319,14 +315,21 @@
if (data_header == nullptr) {
return {};
}
- auto target_entries = ReadType<Idmap_target_entry>(&data_ptr, &data_size, "target",
- dtohl(data_header->target_entry_count));
- if (target_entries == nullptr) {
+ Idmap_target_entries target_entries{
+ .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "entries.target_id",
+ dtohl(data_header->target_entry_count)),
+ .overlay_id = ReadType<uint32_t>(&data_ptr, &data_size, "entries.overlay_id",
+ dtohl(data_header->target_entry_count)),
+ };
+ if (!target_entries.target_id || !target_entries.overlay_id) {
return {};
}
- auto target_inline_entries = ReadType<Idmap_target_entry_inline>(
- &data_ptr, &data_size, "target inline", dtohl(data_header->target_inline_entry_count));
- if (target_inline_entries == nullptr) {
+ Idmap_target_inline_entries target_inline_entries{
+ .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "target inline.target_id",
+ dtohl(data_header->target_inline_entry_count)),
+ .entry = ReadType<Idmap_target_entry_inline>(&data_ptr, &data_size, "target inline.entry",
+ dtohl(data_header->target_inline_entry_count))};
+ if (!target_inline_entries.target_id || !target_inline_entries.entry) {
return {};
}
@@ -344,9 +347,13 @@
return {};
}
- auto overlay_entries = ReadType<Idmap_overlay_entry>(&data_ptr, &data_size, "target inline",
- dtohl(data_header->overlay_entry_count));
- if (overlay_entries == nullptr) {
+ Idmap_overlay_entries overlay_entries{
+ .overlay_id = ReadType<uint32_t>(&data_ptr, &data_size, "overlay entries.overlay_id",
+ dtohl(data_header->overlay_entry_count)),
+ .target_id = ReadType<uint32_t>(&data_ptr, &data_size, "overlay entries.target_id",
+ dtohl(data_header->overlay_entry_count)),
+ };
+ if (!overlay_entries.overlay_id || !overlay_entries.target_id) {
return {};
}
std::optional<std::string_view> string_pool = ReadString(&data_ptr, &data_size, "string pool");
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 64b1f0c..e213fbd 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -40,6 +40,19 @@
struct Idmap_target_entry_inline_value;
struct Idmap_overlay_entry;
+struct Idmap_target_entries {
+ const uint32_t* target_id = nullptr;
+ const uint32_t* overlay_id = nullptr;
+};
+struct Idmap_target_inline_entries {
+ const uint32_t* target_id = nullptr;
+ const Idmap_target_entry_inline* entry = nullptr;
+};
+struct Idmap_overlay_entries {
+ const uint32_t* overlay_id = nullptr;
+ const uint32_t* target_id = nullptr;
+};
+
// A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
// table and additionally allows for loading strings from the idmap string pool. The idmap string
// pool strings are offset after the end of the overlay resource table string pool entries so
@@ -67,7 +80,7 @@
private:
explicit OverlayDynamicRefTable(const Idmap_data_header* data_header,
- const Idmap_overlay_entry* entries,
+ Idmap_overlay_entries entries,
uint8_t target_assigned_package_id);
// Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target
@@ -75,8 +88,8 @@
status_t lookupResourceIdNoRewrite(uint32_t* resId) const;
const Idmap_data_header* data_header_;
- const Idmap_overlay_entry* entries_;
- const int8_t target_assigned_package_id_;
+ Idmap_overlay_entries entries_;
+ uint8_t target_assigned_package_id_;
friend LoadedIdmap;
friend IdmapResMap;
@@ -131,17 +144,15 @@
}
private:
- explicit IdmapResMap(const Idmap_data_header* data_header,
- const Idmap_target_entry* entries,
- const Idmap_target_entry_inline* inline_entries,
+ explicit IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries,
+ Idmap_target_inline_entries inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values,
- const ConfigDescription* configs,
- uint8_t target_assigned_package_id,
+ const ConfigDescription* configs, uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table);
const Idmap_data_header* data_header_;
- const Idmap_target_entry* entries_;
- const Idmap_target_entry_inline* inline_entries_;
+ Idmap_target_entries entries_;
+ Idmap_target_inline_entries inline_entries_;
const Idmap_target_entry_inline_value* inline_entry_values_;
const ConfigDescription* configurations_;
const uint8_t target_assigned_package_id_;
@@ -192,11 +203,11 @@
const Idmap_header* header_;
const Idmap_data_header* data_header_;
- const Idmap_target_entry* target_entries_;
- const Idmap_target_entry_inline* target_inline_entries_;
+ Idmap_target_entries target_entries_;
+ Idmap_target_inline_entries target_inline_entries_;
const Idmap_target_entry_inline_value* inline_entry_values_;
const ConfigDescription* configurations_;
- const Idmap_overlay_entry* overlay_entries_;
+ const Idmap_overlay_entries overlay_entries_;
const std::unique_ptr<ResStringPool> string_pool_;
android::base::unique_fd idmap_fd_;
@@ -207,17 +218,13 @@
private:
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
- explicit LoadedIdmap(const std::string& idmap_path,
- const Idmap_header* header,
- const Idmap_data_header* data_header,
- const Idmap_target_entry* target_entries,
- const Idmap_target_entry_inline* target_inline_entries,
+ explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
+ const Idmap_data_header* data_header, Idmap_target_entries target_entries,
+ Idmap_target_inline_entries target_inline_entries,
const Idmap_target_entry_inline_value* inline_entry_values_,
- const ConfigDescription* configs,
- const Idmap_overlay_entry* overlay_entries,
+ const ConfigDescription* configs, Idmap_overlay_entries overlay_entries,
std::unique_ptr<ResStringPool>&& string_pool,
- std::string_view overlay_apk_path,
- std::string_view target_apk_path);
+ std::string_view overlay_apk_path, std::string_view target_apk_path);
friend OverlayStringPool;
};
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index c264890..e330410 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -48,7 +48,7 @@
namespace android {
constexpr const uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const uint32_t kIdmapCurrentVersion = 0x00000009u;
+constexpr const uint32_t kIdmapCurrentVersion = 0x0000000Au;
// This must never change.
constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endian)
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 8e847e8..7e4b261 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
index e81cbfb..c0ef4b14 100644
--- a/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.cpp
@@ -29,37 +29,6 @@
namespace uirenderer {
namespace skiapipeline {
-BackdropFilterDrawable::~BackdropFilterDrawable() {}
-
-bool BackdropFilterDrawable::prepareToDraw(SkCanvas* canvas, const RenderProperties& properties,
- int backdropImageWidth, int backdropImageHeight) {
- // the drawing bounds for blurred content.
- mDstBounds.setWH(properties.getWidth(), properties.getHeight());
-
- float alphaMultiplier = 1.0f;
- RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true);
-
- // get proper subset for previous content.
- canvas->getTotalMatrix().mapRect(&mImageSubset, mDstBounds);
- SkRect imageSubset(mImageSubset);
- // ensure the subset is inside bounds of previous content.
- if (!mImageSubset.intersect(SkRect::MakeWH(backdropImageWidth, backdropImageHeight))) {
- return false;
- }
-
- // correct the drawing bounds if subset was changed.
- if (mImageSubset != imageSubset) {
- SkMatrix inverse;
- if (canvas->getTotalMatrix().invert(&inverse)) {
- inverse.mapRect(&mDstBounds, mImageSubset);
- }
- }
-
- // follow the alpha from the target RenderNode.
- mPaint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier);
- return true;
-}
-
void BackdropFilterDrawable::onDraw(SkCanvas* canvas) {
const RenderProperties& properties = mTargetRenderNode->properties();
auto* backdropFilter = properties.layerProperties().getBackdropImageFilter();
@@ -68,27 +37,43 @@
return;
}
- auto backdropImage = surface->makeImageSnapshot();
- // sync necessary properties from target RenderNode.
- if (!prepareToDraw(canvas, properties, backdropImage->width(), backdropImage->height())) {
+ SkRect srcBounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
+
+ float alphaMultiplier = 1.0f;
+ RenderNodeDrawable::setViewProperties(properties, canvas, &alphaMultiplier, true);
+ SkPaint paint;
+ paint.setAlpha(properties.layerProperties().alpha() * alphaMultiplier);
+
+ SkRect surfaceSubset;
+ canvas->getTotalMatrix().mapRect(&surfaceSubset, srcBounds);
+ if (!surfaceSubset.intersect(SkRect::MakeWH(surface->width(), surface->height()))) {
return;
}
- auto imageSubset = mImageSubset.roundOut();
+ auto backdropImage = surface->makeImageSnapshot(surfaceSubset.roundOut());
+
+ SkIRect imageBounds = SkIRect::MakeWH(backdropImage->width(), backdropImage->height());
+ SkIPoint offset;
+ SkIRect imageSubset;
+
#ifdef __ANDROID__
if (canvas->recordingContext()) {
backdropImage =
SkImages::MakeWithFilter(canvas->recordingContext(), backdropImage, backdropFilter,
- imageSubset, imageSubset, &mOutSubset, &mOutOffset);
+ imageBounds, imageBounds, &imageSubset, &offset);
} else
#endif
{
- backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageSubset,
- imageSubset, &mOutSubset, &mOutOffset);
+ backdropImage = SkImages::MakeWithFilter(backdropImage, backdropFilter, imageBounds,
+ imageBounds, &imageSubset, &offset);
}
- canvas->drawImageRect(backdropImage, SkRect::Make(mOutSubset), mDstBounds,
- SkSamplingOptions(SkFilterMode::kLinear), &mPaint,
- SkCanvas::kStrict_SrcRectConstraint);
+
+ canvas->save();
+ canvas->resetMatrix();
+ canvas->drawImageRect(backdropImage, SkRect::Make(imageSubset), surfaceSubset,
+ SkSamplingOptions(SkFilterMode::kLinear), &paint,
+ SkCanvas::kFast_SrcRectConstraint);
+ canvas->restore();
}
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/BackdropFilterDrawable.h b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
index 9e35837..5e216a1 100644
--- a/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
+++ b/libs/hwui/pipeline/skia/BackdropFilterDrawable.h
@@ -37,23 +37,10 @@
BackdropFilterDrawable(RenderNode* renderNode, SkCanvas* canvas)
: mTargetRenderNode(renderNode), mBounds(canvas->getLocalClipBounds()) {}
- ~BackdropFilterDrawable();
+ ~BackdropFilterDrawable() = default;
private:
RenderNode* mTargetRenderNode;
- SkPaint mPaint;
-
- SkRect mDstBounds;
- SkRect mImageSubset;
- SkIRect mOutSubset;
- SkIPoint mOutOffset;
-
- /**
- * Check all necessary properties before actual drawing.
- * Return true if ready to draw.
- */
- bool prepareToDraw(SkCanvas* canvas, const RenderProperties& properties, int backdropImageWidth,
- int backdropImageHeight);
protected:
void onDraw(SkCanvas* canvas) override;
diff --git a/libs/hwui/tests/common/scenes/BackdropBlur.cpp b/libs/hwui/tests/common/scenes/BackdropBlur.cpp
new file mode 100644
index 0000000..a1133ff
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/BackdropBlur.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <SkBlendMode.h>
+
+#include "SkImageFilter.h"
+#include "SkImageFilters.h"
+#include "TestSceneBase.h"
+#include "utils/Blur.h"
+
+class BackdropBlurAnimation : public TestScene {
+private:
+ std::unique_ptr<TestScene> listView;
+
+public:
+ explicit BackdropBlurAnimation(const TestScene::Options& opts) {
+ listView.reset(TestScene::testMap()["listview"].createScene(opts));
+ }
+
+ void createContent(int width, int height, Canvas& canvas) override {
+ sp<RenderNode> list = TestUtils::createNode(
+ 0, 0, width, height,
+ [this, width, height](RenderProperties& props, Canvas& canvas) {
+ props.setClipToBounds(false);
+ listView->createContent(width, height, canvas);
+ });
+
+ canvas.drawRenderNode(list.get());
+
+ int x = width / 8;
+ int y = height / 4;
+ sp<RenderNode> blurNode = TestUtils::createNode(
+ x, y, width - x, height - y, [](RenderProperties& props, Canvas& canvas) {
+ props.mutableOutline().setRoundRect(0, 0, props.getWidth(), props.getHeight(),
+ dp(16), 1);
+ props.mutableOutline().setShouldClip(true);
+ sk_sp<SkImageFilter> blurFilter = SkImageFilters::Blur(
+ Blur::convertRadiusToSigma(dp(8)), Blur::convertRadiusToSigma(dp(8)),
+ SkTileMode::kClamp, nullptr, nullptr);
+ props.mutateLayerProperties().setBackdropImageFilter(blurFilter.get());
+ canvas.drawColor(0x33000000, SkBlendMode::kSrcOver);
+ });
+
+ canvas.drawRenderNode(blurNode.get());
+ }
+
+ void doFrame(int frameNr) override { listView->doFrame(frameNr); }
+};
+
+static TestScene::Registrar _BackdropBlur(TestScene::Info{
+ "backdropblur", "A rounded rect that does a blur-behind of a sky animation.",
+ [](const TestScene::Options& opts) -> test::TestScene* {
+ return new BackdropBlurAnimation(opts);
+ }});
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index ca54087..4b29100 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -1280,7 +1280,7 @@
canvas->drawDrawable(&backdropDrawable);
// the drawable is still visible, ok to draw.
EXPECT_EQ(2, canvas->mDrawCounter);
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH - 30, CANVAS_HEIGHT - 30), canvas->mDstBounds);
+ EXPECT_EQ(SkRect::MakeLTRB(30, 30, CANVAS_WIDTH, CANVAS_HEIGHT), canvas->mDstBounds);
canvas->translate(CANVAS_WIDTH, CANVAS_HEIGHT);
canvas->drawDrawable(&drawable);
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index b10019a..67d5774 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -29,6 +29,10 @@
libs: [
"androidx.annotation_annotation",
],
+ stub_only_libs: [
+ // Needed for javadoc references.
+ "framework-location.stubs.system",
+ ],
api_packages: [
"android.location",
"com.android.location.provider",
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 2d7db5e..8b04644 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -16,6 +16,9 @@
package android.media;
+import static com.android.media.flags.Flags.FLAG_UPDATE_CLIENT_PROFILE_PRIORITY;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -970,6 +973,27 @@
registerClient(context, tvInputServiceSessionId, priorityHint);
}
+ /**
+ * Updates client priority with an arbitrary value along with a nice value.
+ *
+ * <p>Tuner resource manager (TRM) uses the client priority value to decide whether it is able
+ * to reclaim insufficient resources from another client.
+ *
+ * <p>The nice value represents how much the client intends to give up the resource when an
+ * insufficient resource situation happens.
+ *
+ * @see <a
+ * href="https://source.android.com/docs/devices/tv/tuner-framework#priority-nice-value">
+ * Priority value and nice value</a>
+ * @param priority the new priority. Any negative value would cause no-op on priority setting
+ * and the API would only process nice value setting in that case.
+ * @param niceValue the nice value.
+ */
+ @FlaggedApi(FLAG_UPDATE_CLIENT_PROFILE_PRIORITY)
+ public boolean updateResourcePriority(int priority, int niceValue) {
+ return mTunerResourceManager.updateClientPriority(mClientId, priority, niceValue);
+ }
+
IHwBinder getBinder() {
if (mICas != null) {
return null; // Return IHwBinder only for HIDL
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 7252135..1ef98f2 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -70,6 +70,13 @@
}
flag {
+ name: "update_client_profile_priority"
+ namespace: "media"
+ description : "Feature flag to add updateResourcePriority api to MediaCas"
+ bug: "300565729"
+}
+
+flag {
name: "enable_built_in_speaker_route_suitability_statuses"
is_exported: true
namespace: "media_solutions"
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index 08155dd..5805332 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -31,6 +31,12 @@
<!-- A header for selfManaged devices only. -->
<include layout="@layout/vendor_header" />
+ <!-- A device icon for selfManaged devices only. -->
+ <ImageView
+ android:id="@+id/device_icon"
+ android:visibility="gone"
+ android:contentDescription="@null"
+ style="@style/DeviceIcon" />
<!-- Do NOT change the ID of the root LinearLayout above:
it's referenced in CTS tests. -->
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index fe7cfc6..a161a50 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -137,4 +137,10 @@
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
</style>
+ <style name="DeviceIcon">
+ <item name="android:layout_width">24dp</item>
+ <item name="android:layout_height">24dp</item>
+ <item name="android:layout_gravity">center</item>
+ </style>
+
</resources>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
index 7974a37..39bbc25 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
@@ -61,6 +61,7 @@
import android.graphics.BlendModeColorFilter;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.MacAddress;
import android.os.Bundle;
import android.os.Handler;
@@ -130,6 +131,8 @@
// Present for single device and multiple device only.
private ImageView mProfileIcon;
+ // Present for self managed association only;
+ private ImageView mDeviceIcon;
// Only present for selfManaged devices.
private ImageView mVendorHeaderImage;
@@ -306,6 +309,8 @@
mVendorHeaderName = findViewById(R.id.vendor_header_name);
mVendorHeaderButton = findViewById(R.id.vendor_header_button);
+ mDeviceIcon = findViewById(R.id.device_icon);
+
mDeviceListRecyclerView = findViewById(R.id.device_list);
mMultipleDeviceSpinner = findViewById(R.id.spinner_multiple_device);
@@ -430,6 +435,7 @@
final Drawable vendorIcon;
final CharSequence vendorName;
final Spanned title;
+ final Icon deviceIcon = mRequest.getDeviceIcon();
if (!SUPPORTED_SELF_MANAGED_PROFILES.contains(deviceProfile)) {
throw new RuntimeException("Unsupported profile " + deviceProfile);
@@ -452,6 +458,11 @@
title = getHtmlFromResources(this, PROFILE_TITLES.get(deviceProfile), mAppLabel,
getString(R.string.device_type), deviceName);
+ if (deviceIcon != null) {
+ mDeviceIcon.setImageIcon(deviceIcon);
+ mDeviceIcon.setVisibility(View.VISIBLE);
+ }
+
if (PROFILE_SUMMARIES.containsKey(deviceProfile)) {
final int summaryResourceId = PROFILE_SUMMARIES.get(deviceProfile);
final Spanned summary = getHtmlFromResources(this, summaryResourceId,
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
index a270681..debaf3e 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.os.Bundle
+import android.util.Log
import androidx.annotation.XmlRes
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
@@ -42,7 +43,9 @@
override fun createPreferenceScreen(factory: PreferenceScreenFactory): PreferenceScreen? {
val context = factory.context
fun createPreferenceScreenFromResource() =
- factory.inflate(getPreferenceScreenResId(context))
+ factory.inflate(getPreferenceScreenResId(context))?.also {
+ Log.i(TAG, "Load screen " + it.key + " from resource")
+ }
val screenCreator =
getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource()
@@ -50,10 +53,12 @@
val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context)
val preferenceScreen =
if (screenCreator.hasCompleteHierarchy()) {
+ Log.i(TAG, "Load screen " + screenCreator.key + " from hierarchy")
factory.getOrCreatePreferenceScreen().apply {
inflatePreferenceHierarchy(preferenceBindingFactory, preferenceHierarchy)
}
} else {
+ Log.i(TAG, "Screen " + screenCreator.key + " is hybrid")
createPreferenceScreenFromResource()?.also {
bindRecursively(it, preferenceBindingFactory, preferenceHierarchy)
} ?: return null
@@ -83,4 +88,8 @@
preferenceScreenBindingHelper?.close()
super.onDestroy()
}
+
+ companion object {
+ private const val TAG = "PreferenceFragment"
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 92da2be..8845d2e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -38,7 +38,6 @@
import android.os.Message;
import android.os.ParcelUuid;
import android.os.SystemClock;
-import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
@@ -1291,12 +1290,10 @@
if (BluetoothUtils.hasConnectedBroadcastSource(this, mBluetoothManager)) {
// Gets summary for the buds which are in the audio sharing.
int groupId = BluetoothUtils.getGroupId(this);
- if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
- && groupId
- == Settings.Secure.getInt(
- mContext.getContentResolver(),
- "bluetooth_le_broadcast_fallback_active_group_id",
- BluetoothCsipSetCoordinator.GROUP_ID_INVALID)) {
+ int primaryGroupId = BluetoothUtils.getPrimaryGroupIdForBroadcast(
+ mContext.getContentResolver());
+ if ((primaryGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID)
+ ? (groupId == primaryGroupId) : isActiveDevice(BluetoothProfile.LE_AUDIO)) {
// The buds are primary buds
return getSummaryWithBatteryInfo(
R.string.bluetooth_active_battery_level_untethered,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
index 9164b64..a72ba8d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
@@ -212,13 +212,14 @@
public int getMaxInputGain() {
// TODO (b/357123335): use real input gain implementation.
- // Using 15 for now since it matches the max index for output.
- return 15;
+ // Using 100 for now since it matches the maximum input gain index in classic ChromeOS.
+ return 100;
}
public int getCurrentInputGain() {
// TODO (b/357123335): use real input gain implementation.
- return 8;
+ // Show a fixed full gain in UI before it really works per UX requirement.
+ return 100;
}
public boolean isInputGainFixed() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 0d81494..70cb2ef 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -1977,12 +1977,12 @@
}
@Test
- public void getConnectionSummary_isBroadcastPrimary_returnActive() {
+ public void getConnectionSummary_isBroadcastPrimary_fallbackDevice_returnActive() {
when(mBroadcast.isEnabled(any())).thenReturn(true);
when(mCachedDevice.getDevice()).thenReturn(mDevice);
Settings.Secure.putInt(
mContext.getContentResolver(),
- "bluetooth_le_broadcast_fallback_active_group_id",
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
1);
List<Long> bisSyncState = new ArrayList<>();
@@ -1992,12 +1992,30 @@
sourceList.add(mLeBroadcastReceiveState);
when(mAssistant.getAllSources(any())).thenReturn(sourceList);
- when(mCachedDevice.getGroupId())
- .thenReturn(
- Settings.Secure.getInt(
- mContext.getContentResolver(),
- "bluetooth_le_broadcast_fallback_active_group_id",
- BluetoothCsipSetCoordinator.GROUP_ID_INVALID));
+ when(mCachedDevice.getGroupId()).thenReturn(1);
+
+ assertThat(mCachedDevice.getConnectionSummary(false))
+ .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
+ }
+
+ @Test
+ public void getConnectionSummary_isBroadcastPrimary_activeDevice_returnActive() {
+ when(mBroadcast.isEnabled(any())).thenReturn(true);
+ when(mCachedDevice.getDevice()).thenReturn(mDevice);
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+ BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+
+ List<Long> bisSyncState = new ArrayList<>();
+ bisSyncState.add(1L);
+ when(mLeBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState);
+ List<BluetoothLeBroadcastReceiveState> sourceList = new ArrayList<>();
+ sourceList.add(mLeBroadcastReceiveState);
+ when(mAssistant.getAllSources(any())).thenReturn(sourceList);
+
+ when(mCachedDevice.getGroupId()).thenReturn(1);
+ when(mCachedDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
assertThat(mCachedDevice.getConnectionSummary(false))
.isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
@@ -2009,7 +2027,7 @@
when(mCachedDevice.getDevice()).thenReturn(mDevice);
Settings.Secure.putInt(
mContext.getContentResolver(),
- "bluetooth_le_broadcast_fallback_active_group_id",
+ BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
1);
List<Long> bisSyncState = new ArrayList<>();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
index 16c0c1c..29cc403 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java
@@ -255,12 +255,12 @@
@Test
public void getMaxInputGain_returnMaxInputGain() {
- assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(15);
+ assertThat(mInputRouteManager.getMaxInputGain()).isEqualTo(100);
}
@Test
public void getCurrentInputGain_returnCurrentInputGain() {
- assertThat(mInputRouteManager.getCurrentInputGain()).isEqualTo(8);
+ assertThat(mInputRouteManager.getCurrentInputGain()).isEqualTo(100);
}
@Test
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index bd7067b..1f10ead 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -1022,6 +1022,7 @@
defaults: [
"platform_app_defaults",
"SystemUI_optimized_defaults",
+ "wmshell_defaults",
],
static_libs: [
"SystemUI-core",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index c6238e8..a21a805 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -813,16 +813,6 @@
}
flag {
- name: "register_zen_mode_content_observer_background"
- namespace: "systemui"
- description: "Decide whether to register zen mode content observers in the background thread."
- bug: "324515627"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "clipboard_noninteractive_on_lockscreen"
namespace: "systemui"
description: "Prevents the interactive clipboard UI from appearing when device is locked"
@@ -1483,3 +1473,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "magic_portrait_wallpapers"
+ namespace: "systemui"
+ description: "Magic Portrait related changes in systemui"
+ bug: "370863642"
+}
+
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt b/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt
deleted file mode 100644
index 97c8076..0000000
--- a/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.compose.activity
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.contentColorFor
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import com.android.compose.rememberSystemUiController
-import com.android.compose.theme.PlatformTheme
-
-/** Scaffolding for an edge-to-edge activity content. */
-@Composable
-fun EdgeToEdgeActivityContent(
- modifier: Modifier = Modifier,
- content: @Composable () -> Unit,
-) {
- // Make the status and navigation bars transparent, ensuring that the status bar icons are dark
- // when the theme is light and vice-versa.
- val systemUiController = rememberSystemUiController()
- val isDarkTheme = isSystemInDarkTheme()
- val useDarkIcons = !isDarkTheme
- DisposableEffect(systemUiController, useDarkIcons) {
- systemUiController.setSystemBarsColor(
- color = Color.Transparent,
- darkIcons = useDarkIcons,
- )
- onDispose {}
- }
-
- PlatformTheme(isDarkTheme) {
- val backgroundColor = MaterialTheme.colorScheme.background
- Box(modifier.fillMaxSize().background(backgroundColor)) {
- CompositionLocalProvider(LocalContentColor provides contentColorFor(backgroundColor)) {
- content()
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
index b28655b..37c37b0 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
@@ -84,40 +84,8 @@
val secondary = getColor(context, R.attr.materialColorSecondary)
val tertiary = getColor(context, R.attr.materialColorTertiary)
- @Deprecated("Use the new android tokens: go/sysui-colors")
- val deprecated = DeprecatedValues(context)
-
- class DeprecatedValues(context: Context) {
- val colorPrimary = getColor(context, R.attr.colorPrimary)
- val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark)
- val colorAccent = getColor(context, R.attr.colorAccent)
- val colorAccentPrimary = getColor(context, R.attr.colorAccentPrimary)
- val colorAccentSecondary = getColor(context, R.attr.colorAccentSecondary)
- val colorAccentTertiary = getColor(context, R.attr.colorAccentTertiary)
- val colorAccentPrimaryVariant = getColor(context, R.attr.colorAccentPrimaryVariant)
- val colorAccentSecondaryVariant = getColor(context, R.attr.colorAccentSecondaryVariant)
- val colorAccentTertiaryVariant = getColor(context, R.attr.colorAccentTertiaryVariant)
- val colorSurface = getColor(context, R.attr.colorSurface)
- val colorSurfaceHighlight = getColor(context, R.attr.colorSurfaceHighlight)
- val colorSurfaceVariant = getColor(context, R.attr.colorSurfaceVariant)
- val colorSurfaceHeader = getColor(context, R.attr.colorSurfaceHeader)
- val colorError = getColor(context, R.attr.colorError)
- val colorBackground = getColor(context, R.attr.colorBackground)
- val colorBackgroundFloating = getColor(context, R.attr.colorBackgroundFloating)
- val panelColorBackground = getColor(context, R.attr.panelColorBackground)
- val textColorPrimary = getColor(context, R.attr.textColorPrimary)
- val textColorSecondary = getColor(context, R.attr.textColorSecondary)
- val textColorTertiary = getColor(context, R.attr.textColorTertiary)
- val textColorPrimaryInverse = getColor(context, R.attr.textColorPrimaryInverse)
- val textColorSecondaryInverse = getColor(context, R.attr.textColorSecondaryInverse)
- val textColorTertiaryInverse = getColor(context, R.attr.textColorTertiaryInverse)
- val textColorOnAccent = getColor(context, R.attr.textColorOnAccent)
- val colorForeground = getColor(context, R.attr.colorForeground)
- val colorForegroundInverse = getColor(context, R.attr.colorForegroundInverse)
- }
-
companion object {
- fun getColor(context: Context, attr: Int): Color {
+ internal fun getColor(context: Context, attr: Int): Color {
val ta = context.obtainStyledAttributes(intArrayOf(attr))
@ColorInt val color = ta.getColor(0, 0)
ta.recycle()
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/SystemUIThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
similarity index 90%
rename from packages/SystemUI/compose/core/tests/src/com/android/compose/theme/SystemUIThemeTest.kt
rename to packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
index fe34017..23538e3 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/SystemUIThemeTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
@@ -27,7 +27,7 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-class SystemUIThemeTest {
+class PlatformThemeTest {
@get:Rule val composeRule = createComposeRule()
@Test
@@ -40,9 +40,7 @@
@Test
fun testAndroidColorsAreAvailableInsideTheme() {
composeRule.setContent {
- PlatformTheme {
- Text("foo", color = LocalAndroidColorScheme.current.deprecated.colorAccent)
- }
+ PlatformTheme { Text("foo", color = LocalAndroidColorScheme.current.primaryFixed) }
}
composeRule.onNodeWithText("foo").assertIsDisplayed()
@@ -52,7 +50,7 @@
fun testAccessingAndroidColorsWithoutThemeThrows() {
assertThrows(IllegalStateException::class.java) {
composeRule.setContent {
- Text("foo", color = LocalAndroidColorScheme.current.deprecated.colorAccent)
+ Text("foo", color = LocalAndroidColorScheme.current.primaryFixed)
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index bf8f6ce..7dc2901 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -522,13 +522,7 @@
val currentSceneKey =
if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
- val state = remember {
- MutableSceneTransitionLayoutState(
- currentSceneKey,
- SceneTransitions,
- enableInterruptions = false,
- )
- }
+ val state = remember { MutableSceneTransitionLayoutState(currentSceneKey, SceneTransitions) }
// Update state whenever currentSceneKey has changed.
LaunchedEffect(state, currentSceneKey) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index b808044..4f1acdc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -46,7 +46,7 @@
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.theme.colorAttr
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
@@ -60,10 +60,7 @@
* the Activity/Fragment/View hosting this Composable once a result is available.
*/
@Composable
-fun PeopleScreen(
- viewModel: PeopleViewModel,
- onResult: (PeopleViewModel.Result) -> Unit,
-) {
+fun PeopleScreen(viewModel: PeopleViewModel, onResult: (PeopleViewModel.Result) -> Unit) {
val priorityTiles by viewModel.priorityTiles.collectAsStateWithLifecycle()
val recentTiles by viewModel.recentTiles.collectAsStateWithLifecycle()
@@ -79,10 +76,9 @@
// Make sure to use the Android colors and not the default Material3 colors to have the exact
// same colors as the View implementation.
- val androidColors = LocalAndroidColorScheme.current.deprecated
Surface(
- color = androidColors.colorBackground,
- contentColor = androidColors.textColorPrimary,
+ color = colorAttr(com.android.internal.R.attr.colorBackground),
+ contentColor = colorAttr(com.android.internal.R.attr.textColorPrimary),
modifier = Modifier.fillMaxSize(),
) {
if (priorityTiles.isNotEmpty() || recentTiles.isNotEmpty()) {
@@ -99,9 +95,7 @@
recentTiles: List<PeopleTileViewModel>,
onTileClicked: (PeopleTileViewModel) -> Unit,
) {
- Column(
- Modifier.sysuiResTag("top_level_with_conversations"),
- ) {
+ Column(Modifier.sysuiResTag("top_level_with_conversations")) {
Column(
Modifier.fillMaxWidth().padding(PeopleSpacePadding),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -126,12 +120,7 @@
Modifier.fillMaxWidth()
.sysuiResTag("scroll_view")
.verticalScroll(rememberScrollState())
- .padding(
- top = 16.dp,
- bottom = PeopleSpacePadding,
- start = 8.dp,
- end = 8.dp,
- ),
+ .padding(top = 16.dp, bottom = PeopleSpacePadding, start = 8.dp, end = 8.dp)
) {
val hasPriorityConversations = priorityTiles.isNotEmpty()
if (hasPriorityConversations) {
@@ -153,13 +142,13 @@
private fun ConversationList(
@StringRes headerTextResource: Int,
tiles: List<PeopleTileViewModel>,
- onTileClicked: (PeopleTileViewModel) -> Unit
+ onTileClicked: (PeopleTileViewModel) -> Unit,
) {
Text(
stringResource(headerTextResource),
Modifier.padding(start = 16.dp),
style = MaterialTheme.typography.labelLarge,
- color = LocalAndroidColorScheme.current.deprecated.colorAccentPrimaryVariant,
+ color = colorAttr(com.android.internal.R.attr.colorAccentPrimaryVariant),
)
Spacer(Modifier.height(10.dp))
@@ -167,7 +156,7 @@
tiles.forEachIndexed { index, tile ->
if (index > 0) {
Divider(
- color = LocalAndroidColorScheme.current.deprecated.colorBackground,
+ color = colorAttr(com.android.internal.R.attr.colorBackground),
thickness = 2.dp,
)
}
@@ -190,14 +179,13 @@
withTopCornerRadius: Boolean,
withBottomCornerRadius: Boolean,
) {
- val androidColors = LocalAndroidColorScheme.current.deprecated
val cornerRadius = dimensionResource(R.dimen.people_space_widget_radius)
val topCornerRadius = if (withTopCornerRadius) cornerRadius else 0.dp
val bottomCornerRadius = if (withBottomCornerRadius) cornerRadius else 0.dp
Surface(
- color = androidColors.colorSurface,
- contentColor = androidColors.textColorPrimary,
+ color = colorAttr(com.android.internal.R.attr.colorSurface),
+ contentColor = colorAttr(com.android.internal.R.attr.textColorPrimary),
shape =
RoundedCornerShape(
topStart = topCornerRadius,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
index 26cc9b9..d483f88 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
@@ -41,13 +41,11 @@
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
-import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.theme.colorAttr
import com.android.systemui.res.R
@Composable
-internal fun PeopleScreenEmpty(
- onGotItClicked: () -> Unit,
-) {
+internal fun PeopleScreenEmpty(onGotItClicked: () -> Unit) {
Column(
Modifier.fillMaxSize().padding(PeopleSpacePadding),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -70,15 +68,14 @@
ExampleTile()
Spacer(Modifier.weight(1f))
- val androidColors = LocalAndroidColorScheme.current
Button(
onGotItClicked,
Modifier.fillMaxWidth().defaultMinSize(minHeight = 56.dp),
colors =
ButtonDefaults.buttonColors(
- containerColor = androidColors.deprecated.colorAccentPrimary,
- contentColor = androidColors.deprecated.textColorOnAccent,
- )
+ containerColor = colorAttr(com.android.internal.R.attr.colorAccentPrimary),
+ contentColor = colorAttr(com.android.internal.R.attr.textColorOnAccent),
+ ),
) {
Text(stringResource(R.string.got_it))
}
@@ -87,11 +84,10 @@
@Composable
private fun ExampleTile() {
- val androidColors = LocalAndroidColorScheme.current
Surface(
shape = RoundedCornerShape(28.dp),
- color = androidColors.deprecated.colorSurface,
- contentColor = androidColors.deprecated.textColorPrimary,
+ color = colorAttr(com.android.internal.R.attr.colorSurface),
+ contentColor = colorAttr(com.android.internal.R.attr.textColorPrimary),
) {
Row(
Modifier.padding(vertical = 20.dp, horizontal = 16.dp),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index e9c5c03..edc4cba 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -199,7 +199,7 @@
QuickSettingsTheme {
val context = LocalContext.current
- LaunchedEffect(key1 = context) {
+ LaunchedEffect(context) {
if (qsView == null) {
qsSceneAdapter.inflate(context)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 417f2b8..2d58c8c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -24,6 +24,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -31,6 +32,8 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalContext
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.OverlayKey
@@ -39,9 +42,13 @@
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+import com.android.systemui.qs.ui.composable.QuickSettingsTheme
import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import javax.inject.Provider
import kotlinx.coroutines.flow.collectLatest
/**
@@ -73,6 +80,7 @@
overlayByKey: Map<OverlayKey, Overlay>,
initialSceneKey: SceneKey,
dataSourceDelegator: SceneDataSourceDelegator,
+ qsSceneAdapter: Provider<QSSceneAdapter>,
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
@@ -118,6 +126,24 @@
}
}
+ // Inflate qsView here so that shade has the correct qqs height in the first measure pass after
+ // rebooting
+ if (
+ viewModel.allContentKeys.contains(Scenes.QuickSettings) ||
+ viewModel.allContentKeys.contains(Scenes.Shade)
+ ) {
+ val qsAdapter = qsSceneAdapter.get()
+ QuickSettingsTheme {
+ val context = LocalContext.current
+ val qsView by qsAdapter.qsView.collectAsStateWithLifecycle()
+ LaunchedEffect(context) {
+ if (qsView == null) {
+ qsAdapter.inflate(context)
+ }
+ }
+ }
+ }
+
Box(
modifier =
Modifier.fillMaxSize().pointerInput(Unit) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 2e8fc14..2657d7c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -234,7 +234,6 @@
canHideOverlay: (OverlayKey) -> Boolean = { true },
canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
stateLinks: List<StateLink> = emptyList(),
- enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
): MutableSceneTransitionLayoutState {
return MutableSceneTransitionLayoutStateImpl(
initialScene,
@@ -245,7 +244,6 @@
canHideOverlay,
canReplaceOverlay,
stateLinks,
- enableInterruptions,
)
}
@@ -261,9 +259,6 @@
true
},
private val stateLinks: List<StateLink> = emptyList(),
-
- // TODO(b/290930950): Remove this flag.
- internal val enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
) : MutableSceneTransitionLayoutState {
private val creationThread: Thread = Thread.currentThread()
@@ -406,13 +401,6 @@
transition.updateOverscrollSpecs(fromSpec = null, toSpec = null)
}
- if (!enableInterruptions) {
- // Set the current transition.
- check(transitionStates.size == 1)
- transitionStates = listOf(transition)
- return
- }
-
when (val currentState = transitionStates.last()) {
is TransitionState.Idle -> {
// Replace [Idle] by [transition].
@@ -755,9 +743,6 @@
private const val TAG = "SceneTransitionLayoutState"
-/** Whether support for interruptions in enabled by default. */
-internal const val DEFAULT_INTERRUPTIONS_ENABLED = true
-
/**
* The max number of concurrent transitions. If the number of transitions goes past this number,
* this probably means that there is a leak and we will Log.wtf before clearing the list of
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index d6751ae..9d3f25e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -337,10 +337,6 @@
}
internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
- if (!layoutImpl.state.enableInterruptions) {
- return 0f
- }
-
if (replacedTransition != null) {
return replacedTransition.interruptionProgress(layoutImpl)
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 1eed54e..a2c2729 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -213,10 +213,6 @@
from(SceneA, to = SceneB) { spec = tween }
from(SceneB, to = SceneC) { spec = tween }
},
-
- // Disable interruptions so that the current transition is directly removed
- // when starting a new one.
- enableInterruptions = false,
)
}
@@ -243,7 +239,12 @@
onElement(TestElements.Bar).assertExists()
// Start transition from SceneB to SceneC
- rule.runOnUiThread { state.setTargetScene(SceneC, coroutineScope) }
+ rule.runOnUiThread {
+ // We snap to scene B so that the transition A => B is removed from the list of
+ // transitions.
+ state.snapToScene(SceneB)
+ state.setTargetScene(SceneC, coroutineScope)
+ }
}
at(3 * frameDuration) { onElement(TestElements.Bar).assertIsNotDisplayed() }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 400f0b3..b00b894b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -85,15 +85,9 @@
/** The content under test. */
@Composable
- private fun TestContent(enableInterruptions: Boolean = true) {
+ private fun TestContent() {
coroutineScope = rememberCoroutineScope()
- layoutState = remember {
- MutableSceneTransitionLayoutState(
- SceneA,
- EmptyTestTransitions,
- enableInterruptions = enableInterruptions,
- )
- }
+ layoutState = remember { MutableSceneTransitionLayoutState(SceneA, EmptyTestTransitions) }
SceneTransitionLayout(state = layoutState, modifier = Modifier.size(LayoutSize)) {
scene(SceneA, userActions = mapOf(Back to SceneB)) {
@@ -205,7 +199,7 @@
@Test
fun testSharedElement() {
- rule.setContent { TestContent(enableInterruptions = false) }
+ rule.setContent { TestContent() }
// In scene A, the shared element SharedFoo() is at the top end of the layout and has a size
// of 50.dp.
@@ -253,6 +247,9 @@
.isWithin(DpOffsetSubject.DefaultTolerance)
.of(DpOffset(25.dp, 25.dp))
+ // Finish the transition.
+ rule.mainClock.advanceTimeBy(TestTransitionDuration / 2)
+
// Animate to scene C, let the animation start then go to the middle of the transition.
currentScene = SceneC
rule.mainClock.advanceTimeByFrame()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 43c7ed6..9c58e2b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
+import com.android.wm.shell.keyguard.KeyguardTransitions
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -46,6 +47,7 @@
@Mock private lateinit var keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier
@Mock
private lateinit var keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor
+ @Mock private lateinit var keyguardTransitions: KeyguardTransitions
@Before
fun setUp() {
@@ -59,6 +61,7 @@
keyguardStateController = keyguardStateController,
keyguardSurfaceBehindAnimator = keyguardSurfaceBehindAnimator,
keyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor,
+ keyguardTransitions = keyguardTransitions,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 5186536..12eadfc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -184,17 +184,6 @@
}
@Test
- fun iconContainer_isVisible_bypassEnabled() =
- testScope.runTest {
- val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
- runCurrent()
- deviceEntryRepository.setBypassEnabled(true)
- runCurrent()
-
- assertThat(isVisible?.value).isTrue()
- }
-
- @Test
fun iconContainer_isNotVisible_pulseExpanding_notBypassing() =
testScope.runTest {
val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
@@ -283,22 +272,23 @@
}
@Test
- fun iconContainer_isNotVisible_bypassDisabled_onLockscreen() =
+ fun iconContainer_isNotVisible_notifsFullyHiddenThenVisible_bypassEnabled() =
testScope.runTest {
val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
runCurrent()
- keyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.AOD,
- to = KeyguardState.LOCKSCREEN,
- testScope,
- )
notificationsKeyguardInteractor.setPulseExpanding(false)
- deviceEntryRepository.setBypassEnabled(false)
+ deviceEntryRepository.setBypassEnabled(true)
whenever(dozeParameters.alwaysOn).thenReturn(true)
whenever(dozeParameters.displayNeedsBlanking).thenReturn(false)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
runCurrent()
+ assertThat(isVisible?.value).isTrue()
+ assertThat(isVisible?.isAnimating).isTrue()
+
+ notificationsKeyguardInteractor.setNotificationsFullyHidden(false)
+ runCurrent()
+
assertThat(isVisible?.value).isFalse()
assertThat(isVisible?.isAnimating).isTrue()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/privacy/PrivacyDialogControllerV2Test.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TileLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/TileLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/model/ScreenRecordModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/AnnouncementResolverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeImageCapture.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeImageCapture.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RecyclerViewActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/RecyclerViewActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/RecyclerViewActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/RecyclerViewActivity.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsScreenshotHelperServiceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/appclips/AppClipsServiceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/model/DisplayContentScenarios.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/data/repository/ProfileTypeRepositoryKosmos.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/TestUserIds.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/TestUserIds.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/TestUserIds.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/TestUserIds.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollCaptureFrameworkSmokeTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/scroll/ScrollViewActivity.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/scrim/ScrimViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/scrim/ScrimViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangeTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangeTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ConstraintChangesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/condition/FakeCondition.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/QuickStepContractTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationListenerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationListenerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/MobileIconCarrierIdOverridesFake.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/CommandQueueInitializerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarOrchestratorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreMocks.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationLoggerViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/FakeDeviceBasedSatelliteViewModel.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
index 5036e77..46f822a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
@@ -21,6 +21,7 @@
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -31,8 +32,10 @@
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith;
@SmallTest
+@RunWith(AndroidJUnit4::class)
class CollapsedStatusBarInteractorTest : SysuiTestCase() {
val kosmos = testKosmos()
val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BlockingQueueIntentReceiver.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 2588f1f..e3bd885 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -61,7 +61,7 @@
import java.util.List;
import java.util.concurrent.Executor;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
@SmallTest
public class BluetoothControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ClockTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ClockTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt
new file mode 100644
index 0000000..9abdf42
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2017 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.policy
+
+import android.app.NotificationManager
+import android.os.Handler
+import android.provider.Settings
+import android.service.notification.ZenModeConfig
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.userTracker
+import com.android.systemui.testKosmos
+import com.android.systemui.util.settings.fakeGlobalSettings
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class ZenModeControllerImplTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var controller: ZenModeControllerImpl
+
+ private val globalSettings = kosmos.fakeGlobalSettings
+ private val config: ZenModeConfig = mock<ZenModeConfig>()
+ private val mNm: NotificationManager = mock<NotificationManager>()
+
+ @Before
+ fun setUp() {
+ testableLooper = TestableLooper.get(this)
+ mContext.addMockSystemService(NotificationManager::class.java, mNm)
+ whenever(mNm.zenModeConfig).thenReturn(config)
+
+ controller =
+ ZenModeControllerImpl(
+ mContext,
+ Handler.createAsync(testableLooper.looper),
+ kosmos.broadcastDispatcher,
+ kosmos.dumpManager,
+ globalSettings,
+ kosmos.userTracker,
+ )
+ }
+
+ @Test
+ fun testRemoveDuringCallback() {
+ val callback =
+ object : ZenModeController.Callback {
+ override fun onConfigChanged(config: ZenModeConfig) {
+ controller.removeCallback(this)
+ }
+ }
+
+ controller.addCallback(callback)
+ val mockCallback = Mockito.mock(ZenModeController.Callback::class.java)
+ controller.addCallback(mockCallback)
+ controller.fireConfigChanged(config)
+ Mockito.verify(mockCallback).onConfigChanged(ArgumentMatchers.eq(config))
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_zenOffShadeSuppressed() {
+ config.suppressedVisualEffects =
+ NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
+ controller.updateZenMode(Settings.Global.ZEN_MODE_OFF)
+ controller.updateZenModeConfig()
+ assertThat(controller.areNotificationsHiddenInShade()).isFalse()
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
+ val policy =
+ NotificationManager.Policy(
+ 0,
+ 0,
+ 0,
+ NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR,
+ )
+ whenever(mNm.consolidatedNotificationPolicy).thenReturn(policy)
+ controller.updateConsolidatedNotificationPolicy()
+ controller.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ assertThat(controller.areNotificationsHiddenInShade()).isFalse()
+ }
+
+ @Test
+ fun testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
+ val policy =
+ NotificationManager.Policy(
+ 0,
+ 0,
+ 0,
+ NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
+ )
+ whenever(mNm.consolidatedNotificationPolicy).thenReturn(policy)
+ controller.updateConsolidatedNotificationPolicy()
+ controller.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ assertThat(controller.areNotificationsHiddenInShade()).isTrue()
+ }
+
+ @Test
+ fun testModeChange() =
+ testScope.runTest {
+ val states =
+ listOf(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_ALARMS,
+ Settings.Global.ZEN_MODE_ALARMS,
+ )
+
+ for (state in states) {
+ globalSettings.putInt(Settings.Global.ZEN_MODE, state)
+ testScope.runCurrent()
+ testableLooper.processAllMessages()
+ assertThat(controller.zen).isEqualTo(state)
+ }
+ }
+
+ @Test
+ fun testModeChange_callbackNotified() =
+ testScope.runTest {
+ val currentState = AtomicInteger(-1)
+
+ val callback: ZenModeController.Callback =
+ object : ZenModeController.Callback {
+ override fun onZenChanged(zen: Int) {
+ currentState.set(zen)
+ }
+ }
+
+ controller.addCallback(callback)
+
+ val states =
+ listOf(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+ Settings.Global.ZEN_MODE_ALARMS,
+ Settings.Global.ZEN_MODE_ALARMS,
+ )
+
+ for (state in states) {
+ globalSettings.putInt(Settings.Global.ZEN_MODE, state)
+ testScope.runCurrent()
+ testableLooper.processAllMessages()
+ assertThat(currentState.get()).isEqualTo(state)
+ }
+ }
+
+ @Test
+ fun testCallbackRemovedWhileDispatching_doesntCrash() =
+ testScope.runTest {
+ val remove = AtomicBoolean(false)
+ globalSettings.putInt(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF)
+ testableLooper.processAllMessages()
+ val callback: ZenModeController.Callback =
+ object : ZenModeController.Callback {
+ override fun onZenChanged(zen: Int) {
+ if (remove.get()) {
+ controller.removeCallback(this)
+ }
+ }
+ }
+ controller.addCallback(callback)
+ controller.addCallback(object : ZenModeController.Callback {})
+
+ remove.set(true)
+
+ globalSettings.putInt(
+ Settings.Global.ZEN_MODE,
+ Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
+ )
+ testScope.runCurrent()
+ testableLooper.processAllMessages()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/bluetooth/FakeBluetoothRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
index 0c27e58..c7c7fdc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStatePerDisplayRepositoryTest.kt
@@ -21,6 +21,7 @@
import android.app.StatusBarManager.WINDOW_STATE_HIDING
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -34,11 +35,13 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.verify
import org.mockito.kotlin.argumentCaptor
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class StatusBarWindowStatePerDisplayRepositoryTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
index b6a3f36..e23e88c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryStoreTest.kt
@@ -19,6 +19,7 @@
import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -33,12 +34,14 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.runner.RunWith
import org.mockito.Mockito.verify
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.reset
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class StatusBarWindowStateRepositoryStoreTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/CreateUserActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/UserCreatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/UserCreatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/NotificationChannelsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/NotificationChannelsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/NotificationChannelsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/LeakDetectorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/LeakDetectorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/ReferenceTestUtilsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/WeakIdentityHashMapTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/CsdWarningDialogTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/CsdWarningDialogTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/CsdWarningDialogTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
index fe5024f..59676ce 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
@@ -17,10 +17,17 @@
package com.android.systemui.wallpapers.data.repository
import android.app.WallpaperInfo
+import android.view.View
import kotlinx.coroutines.flow.MutableStateFlow
/** Fake implementation of the wallpaper repository. */
class FakeWallpaperRepository : WallpaperRepository {
override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null)
override val wallpaperSupportsAmbientMode = MutableStateFlow(false)
+ override var rootView: View? = null
+ private val _notificationStackAbsoluteBottom = MutableStateFlow(0F)
+
+ override fun setNotificationStackAbsoluteBottom(bottom: Float) {
+ _notificationStackAbsoluteBottom.value = bottom
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubblesTestActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubblesTestActivity.java
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8e01e04..431f048 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -315,6 +315,7 @@
};
private final FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
+ private final Object mSimDataLockObject = new Object();
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
@@ -610,14 +611,26 @@
// It is possible for active subscriptions to become invalid (-1), and these will not be
// present in the subscriptionInfo list
- Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry<Integer, SimData> simData = iter.next();
- if (!activeSubIds.contains(simData.getKey())) {
- mSimLogger.logInvalidSubId(simData.getKey());
- iter.remove();
+ synchronized (mSimDataLockObject) {
+ Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry<Integer, SimData> simData = iter.next();
+ if (!activeSubIds.contains(simData.getKey())) {
+ mSimLogger.logInvalidSubId(simData.getKey());
+ iter.remove();
- SimData data = simData.getValue();
+ SimData data = simData.getValue();
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onSimStateChanged(data.subId, data.slotId, data.simState);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < changedSubscriptions.size(); i++) {
+ SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
for (int j = 0; j < mCallbacks.size(); j++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
if (cb != null) {
@@ -625,18 +638,8 @@
}
}
}
+ callbacksRefreshCarrierInfo();
}
-
- for (int i = 0; i < changedSubscriptions.size(); i++) {
- SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
- for (int j = 0; j < mCallbacks.size(); j++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
- if (cb != null) {
- cb.onSimStateChanged(data.subId, data.slotId, data.simState);
- }
- }
- }
- callbacksRefreshCarrierInfo();
}
private void handleAirplaneModeChanged() {
@@ -3376,12 +3379,15 @@
* Removes all valid subscription info from the map for the given slotId.
*/
private void invalidateSlot(int slotId) {
- Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
- while (iter.hasNext()) {
- SimData data = iter.next().getValue();
- if (data.slotId == slotId && SubscriptionManager.isValidSubscriptionId(data.subId)) {
- mSimLogger.logInvalidSubId(data.subId);
- iter.remove();
+ synchronized (mSimDataLockObject) {
+ Iterator<Map.Entry<Integer, SimData>> iter = mSimDatas.entrySet().iterator();
+ while (iter.hasNext()) {
+ SimData data = iter.next().getValue();
+ if (data.slotId == slotId
+ && SubscriptionManager.isValidSubscriptionId(data.subId)) {
+ mSimLogger.logInvalidSubId(data.subId);
+ iter.remove();
+ }
}
}
}
@@ -3408,23 +3414,25 @@
}
// TODO(b/327476182): Preserve SIM_STATE_CARD_IO_ERROR sims in a separate data source.
- SimData data = mSimDatas.get(subId);
- final boolean changed;
- if (data == null) {
- data = new SimData(state, slotId, subId);
- mSimDatas.put(subId, data);
- changed = true; // no data yet; force update
- } else {
- changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
- data.simState = state;
- data.subId = subId;
- data.slotId = slotId;
- }
- if ((changed || becameAbsent)) {
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onSimStateChanged(subId, slotId, state);
+ synchronized (mSimDataLockObject) {
+ SimData data = mSimDatas.get(subId);
+ final boolean changed;
+ if (data == null) {
+ data = new SimData(state, slotId, subId);
+ mSimDatas.put(subId, data);
+ changed = true; // no data yet; force update
+ } else {
+ changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
+ data.simState = state;
+ data.subId = subId;
+ data.slotId = slotId;
+ }
+ if ((changed || becameAbsent)) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onSimStateChanged(subId, slotId, state);
+ }
}
}
}
@@ -3684,9 +3692,11 @@
callback.onKeyguardVisibilityChanged(isKeyguardVisible());
callback.onTelephonyCapable(mTelephonyCapable);
- for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
- final SimData state = data.getValue();
- callback.onSimStateChanged(state.subId, state.slotId, state.simState);
+ synchronized (mSimDataLockObject) {
+ for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
+ final SimData state = data.getValue();
+ callback.onSimStateChanged(state.subId, state.slotId, state.simState);
+ }
}
}
@@ -3823,19 +3833,23 @@
}
public int getSimState(int subId) {
- if (mSimDatas.containsKey(subId)) {
- return mSimDatas.get(subId).simState;
- } else {
- return TelephonyManager.SIM_STATE_UNKNOWN;
+ synchronized (mSimDataLockObject) {
+ if (mSimDatas.containsKey(subId)) {
+ return mSimDatas.get(subId).simState;
+ } else {
+ return TelephonyManager.SIM_STATE_UNKNOWN;
+ }
}
}
private int getSlotId(int subId) {
- if (!mSimDatas.containsKey(subId)) {
- refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+ synchronized (mSimDataLockObject) {
+ if (!mSimDatas.containsKey(subId)) {
+ refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+ }
+ SimData simData = mSimDatas.get(subId);
+ return simData != null ? simData.slotId : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
- SimData simData = mSimDatas.get(subId);
- return simData != null ? simData.slotId : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@@ -3876,22 +3890,24 @@
*/
private boolean refreshSimState(int subId, int slotId) {
int state = mTelephonyManager.getSimState(slotId);
- SimData data = mSimDatas.get(subId);
+ synchronized (mSimDataLockObject) {
+ SimData data = mSimDatas.get(subId);
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- invalidateSlot(slotId);
- }
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ invalidateSlot(slotId);
+ }
- final boolean changed;
- if (data == null) {
- data = new SimData(state, slotId, subId);
- mSimDatas.put(subId, data);
- changed = true; // no data yet; force update
- } else {
- changed = data.simState != state;
- data.simState = state;
+ final boolean changed;
+ if (data == null) {
+ data = new SimData(state, slotId, subId);
+ mSimDatas.put(subId, data);
+ changed = true; // no data yet; force update
+ } else {
+ changed = data.simState != state;
+ data.simState = state;
+ }
+ return changed;
}
- return changed;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 462e820..b56ed8c 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -16,16 +16,25 @@
package com.android.systemui.display
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.display.data.repository.DeviceStateRepositoryImpl
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.DisplayRepositoryImpl
+import com.android.systemui.display.data.repository.DisplayScopeRepository
+import com.android.systemui.display.data.repository.DisplayScopeRepositoryImpl
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import dagger.Binds
+import dagger.Lazy
import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
/** Module binding display related classes. */
@Module
@@ -46,4 +55,22 @@
fun bindsFocusedDisplayRepository(
focusedDisplayRepository: FocusedDisplayRepositoryImpl
): FocusedDisplayRepository
+
+ @Binds fun displayScopeRepository(impl: DisplayScopeRepositoryImpl): DisplayScopeRepository
+
+ companion object {
+ @Provides
+ @SysUISingleton
+ @IntoMap
+ @ClassKey(DisplayScopeRepositoryImpl::class)
+ fun displayScopeRepoCoreStartable(
+ repoImplLazy: Lazy<DisplayScopeRepositoryImpl>
+ ): CoreStartable {
+ return if (StatusBarConnectedDisplays.isEnabled) {
+ repoImplLazy.get()
+ } else {
+ CoreStartable.NOP
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index e68aba5..6a69136 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -61,8 +61,11 @@
/** Display addition event indicating a new display has been added. */
val displayAdditionEvent: Flow<Display?>
+ /** Display removal event indicating a display has been removed. */
+ val displayRemovalEvent: Flow<Int>
+
/** Provides the current set of displays. */
- val displays: Flow<Set<Display>>
+ val displays: StateFlow<Set<Display>>
/**
* Pending display id that can be enabled/disabled.
@@ -79,8 +82,8 @@
*
* This method is guaranteed to not result in any binder call.
*/
- suspend fun getDisplay(displayId: Int): Display? =
- displays.first().firstOrNull { it.displayId == displayId }
+ fun getDisplay(displayId: Int): Display? =
+ displays.value.firstOrNull { it.displayId == displayId }
/** Represents a connected display that has not been enabled yet. */
interface PendingDisplay {
@@ -148,6 +151,9 @@
getDisplayFromDisplayManager(it.displayId)
}
+ override val displayRemovalEvent: Flow<Int> =
+ allDisplayEvents.filterIsInstance<DisplayEvent.Removed>().map { it.displayId }
+
// This is necessary because there might be multiple displays, and we could
// have missed events for those added before this process or flow started.
// Note it causes a binder call from the main thread (it's traced).
@@ -180,7 +186,7 @@
*
* Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
*/
- private val enabledDisplays: Flow<Set<Display>> =
+ private val enabledDisplays: StateFlow<Set<Display>> =
enabledDisplayIds
.mapElementsLazily { displayId -> getDisplayFromDisplayManager(displayId) }
.onEach {
@@ -204,7 +210,7 @@
*
* Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
*/
- override val displays: Flow<Set<Display>> = enabledDisplays
+ override val displays: StateFlow<Set<Display>> = enabledDisplays
val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
private val ignoredDisplayIds: Flow<Set<Int>> = _ignoredDisplayIds.debugLog("ignoredDisplayIds")
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
new file mode 100644
index 0000000..3062475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 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.display.data.repository
+
+import android.view.Display
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+
+/**
+ * Provides per display instances of [CoroutineScope]. These will remain active as long as the
+ * display is connected, and automatically cancelled when the display is removed.
+ */
+interface DisplayScopeRepository {
+ fun scopeForDisplay(displayId: Int): CoroutineScope
+}
+
+@SysUISingleton
+class DisplayScopeRepositoryImpl
+@Inject
+constructor(
+ @Background private val backgroundApplicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val displayRepository: DisplayRepository,
+) : DisplayScopeRepository, CoreStartable {
+
+ private val perDisplayScopes = ConcurrentHashMap<Int, CoroutineScope>()
+
+ override fun scopeForDisplay(displayId: Int): CoroutineScope {
+ return perDisplayScopes.computeIfAbsent(displayId) { createScopeForDisplay(displayId) }
+ }
+
+ override fun start() {
+ StatusBarConnectedDisplays.assertInNewMode()
+ backgroundApplicationScope.launch {
+ displayRepository.displayRemovalEvent.collect { displayId ->
+ val scope = perDisplayScopes.remove(displayId)
+ scope?.cancel("Display $displayId has been removed.")
+ }
+ }
+ }
+
+ private fun createScopeForDisplay(displayId: Int): CoroutineScope {
+ return if (displayId == Display.DEFAULT_DISPLAY) {
+ // The default display is connected all the time, therefore we can optimise by reusing
+ // the application scope, and don't need to create a new scope.
+ backgroundApplicationScope
+ } else {
+ CoroutineScope(
+ backgroundDispatcher + createCoroutineTracingContext("DisplayScope$displayId")
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 5e05dab..b2acc2a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -24,6 +24,7 @@
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
+import androidx.compose.foundation.border
import androidx.compose.foundation.focusable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
@@ -80,25 +81,18 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
-import androidx.compose.ui.geometry.CornerRadius
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
@@ -113,9 +107,9 @@
import androidx.compose.ui.util.fastFirstOrNull
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
-import androidx.compose.ui.zIndex
+import com.android.compose.modifiers.thenIf
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
@@ -405,7 +399,7 @@
if (index > 0) {
HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHigh)
}
- ShortcutView(Modifier.padding(vertical = 24.dp), searchQuery, shortcut)
+ Shortcut(Modifier.padding(vertical = 24.dp), searchQuery, shortcut)
}
}
@@ -444,9 +438,9 @@
NoSearchResultsText(horizontalPadding = 24.dp, fillHeight = false)
return
}
- LazyColumn(modifier.nestedScroll(rememberNestedScrollInteropConnection())) {
- items(items = category.subCategories, key = { item -> item.label }) {
- SubCategoryContainerDualPane(searchQuery, it)
+ LazyColumn(modifier = modifier) {
+ items(category.subCategories) { subcategory ->
+ SubCategoryContainerDualPane(searchQuery = searchQuery, subCategory = subcategory)
Spacer(modifier = Modifier.height(8.dp))
}
}
@@ -477,14 +471,21 @@
shape = RoundedCornerShape(28.dp),
color = MaterialTheme.colorScheme.surfaceBright,
) {
- Column(Modifier.padding(24.dp)) {
+ Column(Modifier.padding(16.dp)) {
SubCategoryTitle(subCategory.label)
Spacer(Modifier.height(8.dp))
subCategory.shortcuts.fastForEachIndexed { index, shortcut ->
if (index > 0) {
- HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHigh)
+ HorizontalDivider(
+ modifier = Modifier.padding(horizontal = 8.dp),
+ color = MaterialTheme.colorScheme.surfaceContainerHigh,
+ )
}
- ShortcutView(Modifier.padding(vertical = 16.dp), searchQuery, shortcut)
+ Shortcut(
+ modifier = Modifier.padding(vertical = 8.dp),
+ searchQuery = searchQuery,
+ shortcut = shortcut,
+ )
}
}
}
@@ -500,18 +501,17 @@
}
@Composable
-private fun ShortcutView(modifier: Modifier, searchQuery: String, shortcut: Shortcut) {
+private fun Shortcut(modifier: Modifier, searchQuery: String, shortcut: ShortcutModel) {
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
+ val focusColor = MaterialTheme.colorScheme.secondary
Row(
modifier
+ .thenIf(isFocused) {
+ Modifier.border(width = 3.dp, color = focusColor, shape = RoundedCornerShape(16.dp))
+ }
.focusable(interactionSource = interactionSource)
- .outlineFocusModifier(
- isFocused = isFocused,
- focusColor = MaterialTheme.colorScheme.secondary,
- padding = 8.dp,
- cornerRadius = 16.dp,
- )
+ .padding(8.dp)
) {
Row(
modifier = Modifier.width(128.dp).align(Alignment.CenterVertically),
@@ -523,7 +523,7 @@
}
ShortcutDescriptionText(searchQuery = searchQuery, shortcut = shortcut)
}
- Spacer(modifier = Modifier.width(16.dp))
+ Spacer(modifier = Modifier.width(24.dp))
ShortcutKeyCombinations(modifier = Modifier.weight(1f), shortcut = shortcut)
}
}
@@ -548,7 +548,7 @@
@OptIn(ExperimentalLayoutApi::class)
@Composable
-private fun ShortcutKeyCombinations(modifier: Modifier = Modifier, shortcut: Shortcut) {
+private fun ShortcutKeyCombinations(modifier: Modifier = Modifier, shortcut: ShortcutModel) {
FlowRow(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
@@ -628,7 +628,7 @@
@Composable
private fun ShortcutDescriptionText(
searchQuery: String,
- shortcut: Shortcut,
+ shortcut: ShortcutModel,
modifier: Modifier = Modifier,
) {
Text(
@@ -751,39 +751,6 @@
}
}
-private fun Modifier.outlineFocusModifier(
- isFocused: Boolean,
- focusColor: Color,
- padding: Dp,
- cornerRadius: Dp,
-): Modifier {
- if (isFocused) {
- return this.drawWithContent {
- val focusOutline =
- Rect(Offset.Zero, size).let {
- if (padding > 0.dp) {
- it.inflate(padding.toPx())
- } else {
- it.deflate(padding.unaryMinus().toPx())
- }
- }
- drawContent()
- drawRoundRect(
- color = focusColor,
- style = Stroke(width = 3.dp.toPx()),
- topLeft = focusOutline.topLeft,
- size = focusOutline.size,
- cornerRadius = CornerRadius(cornerRadius.toPx()),
- )
- }
- // Increasing Z-Index so focus outline is drawn on top of "selected" category
- // background.
- .zIndex(1f)
- } else {
- return this
- }
-}
-
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun TitleBar() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 9c7cc81..2052459 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -178,6 +178,7 @@
import com.android.systemui.util.settings.SystemSettings;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
+import com.android.window.flags.Flags;
import com.android.wm.shell.keyguard.KeyguardTransitions;
import dagger.Lazy;
@@ -236,6 +237,9 @@
*/
public class KeyguardViewMediator implements CoreStartable, Dumpable,
StatusBarStateController.StateListener {
+
+ private static final boolean ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS =
+ Flags.ensureKeyguardDoesTransitionStarting();
private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
@@ -2865,9 +2869,14 @@
return;
}
- try {
- mActivityTaskManagerService.setLockScreenShown(showing, aodShowing);
- } catch (RemoteException ignored) {
+ if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+ mKeyguardTransitions.startKeyguardTransition(showing, aodShowing);
+ } else {
+ try {
+
+ mActivityTaskManagerService.setLockScreenShown(showing, aodShowing);
+ } catch (RemoteException ignored) {
+ }
}
});
}
@@ -2998,18 +3007,23 @@
// Handled in WmLockscreenVisibilityManager if flag is enabled.
if (!KeyguardWmStateRefactor.isEnabled()) {
- // Don't actually hide the Keyguard at the moment, wait for window manager
- // until it tells us it's safe to do so with startKeyguardExitAnimation.
- // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager
- // will be in order.
- final int keyguardFlag = flags;
- mUiBgExecutor.execute(() -> {
- try {
- mActivityTaskManagerService.keyguardGoingAway(keyguardFlag);
- } catch (RemoteException e) {
- Log.e(TAG, "Error while calling WindowManager", e);
- }
- });
+ // Don't actually hide the Keyguard at the moment, wait for window manager
+ // until it tells us it's safe to do so with startKeyguardExitAnimation.
+ // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager
+ // will be in order.
+ final int keyguardFlag = flags;
+ mUiBgExecutor.execute(() -> {
+ if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+ mKeyguardTransitions.startKeyguardTransition(
+ false /* keyguardShowing */, false /* aodShowing */);
+ return;
+ }
+ try {
+ mActivityTaskManagerService.keyguardGoingAway(keyguardFlag);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error while calling WindowManager", e);
+ }
+ });
}
Trace.endSection();
@@ -3464,6 +3478,12 @@
public void showSurfaceBehindKeyguard() {
mSurfaceBehindRemoteAnimationRequested = true;
+ if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+ mKeyguardTransitions.startKeyguardTransition(
+ false /* keyguardShowing */, false /* aodShowing */);
+ return;
+ }
+
try {
int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
| KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index e89594e..032af94 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -26,6 +26,8 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.window.flags.Flags
+import com.android.wm.shell.keyguard.KeyguardTransitions
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -42,6 +44,7 @@
private val keyguardStateController: KeyguardStateController,
private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier,
private val keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor,
+ private val keyguardTransitions: KeyguardTransitions
) {
/**
@@ -97,6 +100,9 @@
/** Callback provided by WM to call once we're done with the going away animation. */
private var goingAwayRemoteAnimationFinishedCallback: IRemoteAnimationFinishedCallback? = null
+ private val enableNewKeyguardShellTransitions: Boolean =
+ Flags.ensureKeyguardDoesTransitionStarting()
+
/**
* Set the visibility of the surface behind the keyguard, making the appropriate calls to Window
* Manager to effect the change.
@@ -114,7 +120,14 @@
return
}
+
+
if (visible) {
+ if (enableNewKeyguardShellTransitions) {
+ keyguardTransitions.startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */)
+ isKeyguardGoingAway = true
+ return
+ }
// Make the surface visible behind the keyguard by calling keyguardGoingAway. The
// lockscreen is still showing as well, allowing us to animate unlocked.
Log.d(TAG, "ActivityTaskManagerService#keyguardGoingAway()")
@@ -220,7 +233,11 @@
"isLockscreenShowing=$lockscreenShowing, " +
"aodVisible=$aodVisible)."
)
- activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
+ if (enableNewKeyguardShellTransitions) {
+ keyguardTransitions.startKeyguardTransition(lockscreenShowing, aodVisible)
+ } else {
+ activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
+ }
this.isLockscreenShowing = lockscreenShowing
this.isAodVisible = aodVisible
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index ec52055..95d1b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -68,11 +68,16 @@
val previewClock: Flow<ClockController>
+ /** top of notifications without bcsmartspace in small clock settings */
+ val notificationDefaultTop: StateFlow<Float>
+
val clockEventController: ClockEventController
val shouldForceSmallClock: Boolean
fun setClockSize(size: ClockSize)
+
+ fun setNotificationDefaultTop(top: Float)
}
@SysUISingleton
@@ -108,7 +113,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = getClockSize()
+ initialValue = getClockSize(),
)
override val currentClockId: Flow<ClockId> =
@@ -138,7 +143,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = clockRegistry.createCurrentClock()
+ initialValue = clockRegistry.createCurrentClock(),
)
override val previewClock: Flow<ClockController> =
@@ -149,6 +154,14 @@
clockRegistry.createCurrentClock()
}
+ private val _notificationDefaultTop: MutableStateFlow<Float> = MutableStateFlow(0F)
+
+ override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow()
+
+ override fun setNotificationDefaultTop(top: Float) {
+ _notificationDefaultTop.value = top
+ }
+
override val shouldForceSmallClock: Boolean
get() =
featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) &&
@@ -160,7 +173,7 @@
secureSettings.getIntForUser(
Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
/* defaultValue= */ 1,
- UserHandle.USER_CURRENT
+ UserHandle.USER_CURRENT,
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 130242f..8210174 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -269,6 +269,9 @@
*/
val isEncryptedOrLockdown: Flow<Boolean>
+ /** The top of shortcut in screen, used by wallpaper to find remaining space in lockscreen */
+ val shortcutAbsoluteTop: StateFlow<Float>
+
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -339,6 +342,8 @@
* otherwise.
*/
fun isShowKeyguardWhenReenabled(): Boolean
+
+ fun setShortcutAbsoluteTop(top: Float)
}
/** Encapsulates application state for the keyguard. */
@@ -503,7 +508,7 @@
trySendWithFailureLogging(
statusBarStateController.dozeAmount,
TAG,
- "initial dozeAmount"
+ "initial dozeAmount",
)
awaitClose { statusBarStateController.removeCallback(callback) }
@@ -521,7 +526,7 @@
object : DozeTransitionCallback {
override fun onDozeTransition(
oldState: DozeMachine.State,
- newState: DozeMachine.State
+ newState: DozeMachine.State,
) {
trySendWithFailureLogging(
DozeTransitionModel(
@@ -529,7 +534,7 @@
to = dozeMachineStateToModel(newState),
),
TAG,
- "doze transition model"
+ "doze transition model",
)
}
}
@@ -541,7 +546,7 @@
to = dozeMachineStateToModel(dozeTransitionListener.newState),
),
TAG,
- "initial doze transition model"
+ "initial doze transition model",
)
awaitClose { dozeTransitionListener.removeCallback(callback) }
@@ -579,7 +584,7 @@
trySendWithFailureLogging(
statusBarStateIntToObject(state),
TAG,
- "state"
+ "state",
)
}
}
@@ -590,7 +595,7 @@
.stateIn(
scope,
SharingStarted.Eagerly,
- statusBarStateIntToObject(statusBarStateController.state)
+ statusBarStateIntToObject(statusBarStateController.state),
)
private val _biometricUnlockState: MutableStateFlow<BiometricUnlockModel> =
@@ -610,7 +615,7 @@
trySendWithFailureLogging(
authController.fingerprintSensorLocation,
TAG,
- "AuthController.Callback#onFingerprintLocationChanged"
+ "AuthController.Callback#onFingerprintLocationChanged",
)
}
@@ -635,6 +640,9 @@
private val _isActiveDreamLockscreenHosted = MutableStateFlow(false)
override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow()
+ private val _shortcutAbsoluteTop = MutableStateFlow(0F)
+ override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow()
+
init {
val callback =
object : KeyguardStateController.Callback {
@@ -721,6 +729,10 @@
}
}
+ override fun setShortcutAbsoluteTop(top: Float) {
+ _shortcutAbsoluteTop.value = top
+ }
+
private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel {
return when (state) {
DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index c0049d4..5b7eedd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -94,7 +94,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = ClockSize.LARGE
+ initialValue = ClockSize.LARGE,
)
} else {
keyguardClockRepository.clockSize
@@ -152,4 +152,8 @@
clock.largeClock.animations.fold(foldFraction)
}
}
+
+ fun setNotificationStackDefaultTop(top: Float) {
+ keyguardClockRepository.setNotificationDefaultTop(top)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index e6ee112..d7f96b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -526,6 +526,10 @@
repository.showDismissibleKeyguard()
}
+ fun setShortcutAbsoluteTop(top: Float) {
+ repository.setShortcutAbsoluteTop(top)
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index a1c963b..d745522 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -44,6 +44,7 @@
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceLayout
import com.android.systemui.res.R
+import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.shared.R as sharedR
import com.android.systemui.util.ui.value
import dagger.Lazy
@@ -53,6 +54,9 @@
internal fun ConstraintSet.setVisibility(views: Iterable<View>, visibility: Int) =
views.forEach { view -> this.setVisibility(view.id, visibility) }
+internal fun ConstraintSet.setAlpha(views: Iterable<View>, alpha: Float) =
+ views.forEach { view -> this.setAlpha(view.id, alpha) }
+
internal fun ConstraintSet.setScaleX(views: Iterable<View>, scaleX: Float) =
views.forEach { view -> this.setScaleX(view.id, scaleX) }
@@ -70,6 +74,7 @@
val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
private val rootViewModel: KeyguardRootViewModel,
private val aodBurnInViewModel: AodBurnInViewModel,
+ private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>,
) : KeyguardSection() {
private var disposableHandle: DisposableHandle? = null
@@ -123,6 +128,8 @@
return constraintSet.apply {
setVisibility(getTargetClockFace(clock).views, VISIBLE)
setVisibility(getNonTargetClockFace(clock).views, GONE)
+ setAlpha(getTargetClockFace(clock).views, 1F)
+ setAlpha(getNonTargetClockFace(clock).views, 0F)
if (!keyguardClockViewModel.isLargeClockVisible.value) {
connect(sharedR.id.bc_smartspace_view, TOP, sharedR.id.date_smartspace_view, BOTTOM)
} else {
@@ -172,7 +179,7 @@
}
}
- open fun applyDefaultConstraints(constraints: ConstraintSet) {
+ fun applyDefaultConstraints(constraints: ConstraintSet) {
val guideline =
if (keyguardClockViewModel.clockShouldBeCentered.value) PARENT_ID
else R.id.split_shade_guideline
@@ -211,6 +218,28 @@
// Explicitly clear pivot to force recalculate pivot instead of using legacy value
setTransformPivot(R.id.lockscreen_clock_view_large, Float.NaN, Float.NaN)
+
+ val smallClockBottom =
+ keyguardClockViewModel.getSmallClockTopMargin() +
+ context.resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
+ )
+ val dateWeatherSmartspaceHeight = getDimen(context, DATE_WEATHER_VIEW_HEIGHT).toFloat()
+ val marginBetweenSmartspaceAndNotification =
+ context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_status_view_bottom_margin
+ ) +
+ if (context.resources.getBoolean(R.bool.config_use_large_screen_shade_header)) {
+ largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight()
+ } else {
+ 0
+ }
+
+ clockInteractor.setNotificationStackDefaultTop(
+ smallClockBottom +
+ dateWeatherSmartspaceHeight +
+ marginBetweenSmartspaceAndNotification
+ )
}
constrainWeatherClockDateIconsBarrier(constraints)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index 6c6e14c..d3895de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -30,6 +30,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
@@ -52,6 +53,7 @@
private val indicationController: KeyguardIndicationController,
private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
private val keyguardQuickAffordanceViewBinder: KeyguardQuickAffordanceViewBinder,
+ private val keyguardInteractor: KeyguardInteractor,
) : BaseShortcutSection() {
// Amount to increase the bottom margin by to avoid colliding with inset
@@ -117,7 +119,7 @@
BOTTOM,
PARENT_ID,
BOTTOM,
- verticalOffsetMargin + safeInsetBottom
+ verticalOffsetMargin + safeInsetBottom,
)
constrainWidth(R.id.end_button, width)
@@ -128,7 +130,7 @@
BOTTOM,
PARENT_ID,
BOTTOM,
- verticalOffsetMargin + safeInsetBottom
+ verticalOffsetMargin + safeInsetBottom,
)
// The constraint set visibility for start and end button are default visible, set to
@@ -136,5 +138,13 @@
setVisibilityMode(R.id.start_button, VISIBILITY_MODE_IGNORE)
setVisibilityMode(R.id.end_button, VISIBILITY_MODE_IGNORE)
}
+
+ val shortcutAbsoluteTopInScreen =
+ (resources.displayMetrics.heightPixels -
+ (verticalOffsetMargin + safeInsetBottom) -
+ height)
+ .toFloat()
+
+ keyguardInteractor.setShortcutAbsoluteTop(shortcutAbsoluteTopInScreen)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 3705c2c..40d4193 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -347,12 +347,8 @@
when {
// If there are no notification icons to show, then it can be hidden
!hasAodIcons -> false
- // If we're bypassing, then we're visible
- isBypassEnabled -> true
// If we are pulsing (and not bypassing), then we are hidden
isPulseExpanding -> false
- // Besides bypass above, they should not be visible on lockscreen
- isOnLockscreen -> false
// If notifs are fully gone, then we're visible
areNotifsFullyHidden -> true
// Otherwise, we're hidden
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 1511f31..fa987dd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -255,7 +255,8 @@
* @return size in pixels of QQS
*/
public int getQqsHeight() {
- return mHeader.getHeight();
+ SceneContainerFlag.assertInNewMode();
+ return mHeader.getMeasuredHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 8a2e274..cd38ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -6,6 +6,7 @@
import android.view.View
import android.view.WindowInsets
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.scene.ui.composable.Overlay
@@ -13,19 +14,13 @@
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
import com.android.systemui.shade.TouchLogger
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
/** A root view of the main SysUI window that supports scenes. */
@ExperimentalCoroutinesApi
-class SceneWindowRootView(
- context: Context,
- attrs: AttributeSet?,
-) :
- WindowRootView(
- context,
- attrs,
- ) {
+class SceneWindowRootView(context: Context, attrs: AttributeSet?) : WindowRootView(context, attrs) {
private var motionEventHandler: SceneContainerViewModel.MotionEventHandler? = null
// TODO(b/298525212): remove once Compose exposes window inset bounds.
@@ -39,6 +34,7 @@
overlays: Set<Overlay>,
layoutInsetController: LayoutInsetsController,
sceneDataSourceDelegator: SceneDataSourceDelegator,
+ qsSceneAdapter: Provider<QSSceneAdapter>,
alternateBouncerDependencies: AlternateBouncerDependencies,
) {
setLayoutInsetsController(layoutInsetController)
@@ -57,6 +53,7 @@
super.setVisibility(if (isVisible) View.VISIBLE else View.INVISIBLE)
},
dataSourceDelegator = sceneDataSourceDelegator,
+ qsSceneAdapter = qsSceneAdapter,
alternateBouncerDependencies = alternateBouncerDependencies,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
index 38f4e73..1e3a233 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -42,6 +42,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.setSnapshotBinding
import com.android.systemui.lifecycle.viewModel
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -51,6 +52,7 @@
import com.android.systemui.scene.ui.composable.SceneContainer
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.awaitCancellation
@@ -74,6 +76,7 @@
overlays: Set<Overlay>,
onVisibilityChangedInternal: (isVisible: Boolean) -> Unit,
dataSourceDelegator: SceneDataSourceDelegator,
+ qsSceneAdapter: Provider<QSSceneAdapter>,
alternateBouncerDependencies: AlternateBouncerDependencies,
) {
val unsortedSceneByKey: Map<SceneKey, Scene> = scenes.associateBy { scene -> scene.key }
@@ -132,6 +135,7 @@
sceneByKey = sortedSceneByKey,
overlayByKey = sortedOverlayByKey,
dataSourceDelegator = dataSourceDelegator,
+ qsSceneAdapter = qsSceneAdapter,
containerConfig = containerConfig,
)
.also { it.id = R.id.scene_container_root_composable }
@@ -177,6 +181,7 @@
sceneByKey: Map<SceneKey, Scene>,
overlayByKey: Map<OverlayKey, Overlay>,
dataSourceDelegator: SceneDataSourceDelegator,
+ qsSceneAdapter: Provider<QSSceneAdapter>,
containerConfig: SceneContainerConfig,
): View {
return ComposeView(context).apply {
@@ -192,6 +197,7 @@
overlayByKey = overlayByKey,
initialSceneKey = containerConfig.initialSceneKey,
dataSourceDelegator = dataSourceDelegator,
+ qsSceneAdapter = qsSceneAdapter,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 889380a..ce942fe 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -73,6 +73,8 @@
/** Whether the container is visible. */
val isVisible: Boolean by hydrator.hydratedStateOf("isVisible", sceneInteractor.isVisible)
+ val allContentKeys: List<ContentKey> = sceneInteractor.allContentKeys
+
private val hapticsViewModel = hapticsViewModelFactory.create(view)
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt b/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt
index 7b56688..6d3b9aa 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/HeadlessScreenshotHandler.kt
@@ -19,7 +19,6 @@
import android.net.Uri
import android.os.UserManager
import android.util.Log
-import android.view.WindowManager
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
@@ -51,10 +50,6 @@
finisher: Consumer<Uri?>,
requestCallback: TakeScreenshotService.RequestCallback,
) {
- if (screenshot.type == WindowManager.TAKE_SCREENSHOT_FULLSCREEN) {
- screenshot.bitmap = imageCapture.captureDisplay(screenshot.displayId, crop = null)
- }
-
if (screenshot.bitmap == null) {
Log.e(TAG, "handleScreenshot: Screenshot bitmap was null")
notificationsControllerFactory
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
index e589600..acfcd13 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotController.java
@@ -255,12 +255,6 @@
Assert.isMainThread();
mCurrentRequestCallback = requestCallback;
- if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN
- && screenshot.getBitmap() == null) {
- Rect bounds = getFullScreenRect();
- screenshot.setBitmap(mImageCapture.captureDisplay(mDisplay.getDisplayId(), bounds));
- screenshot.setScreenBounds(bounds);
- }
if (screenshot.getBitmap() == null) {
Log.e(TAG, "handleScreenshot: Screenshot bitmap was null");
@@ -323,24 +317,25 @@
attachWindow();
+ Rect bounds = screenshot.getOriginalScreenBounds();
boolean showFlash;
if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- if (screenshot.getScreenBounds() != null
- && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getInsets(),
- screenshot.getScreenBounds())) {
+ if (bounds != null
+ && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getOriginalInsets(),
+ bounds)) {
showFlash = false;
} else {
showFlash = true;
- screenshot.setInsets(Insets.NONE);
- screenshot.setScreenBounds(new Rect(0, 0, screenshot.getBitmap().getWidth(),
- screenshot.getBitmap().getHeight()));
+ bounds = new Rect(0, 0, screenshot.getBitmap().getWidth(),
+ screenshot.getBitmap().getHeight());
}
} else {
showFlash = true;
}
+ final Rect animationBounds = bounds;
mViewProxy.prepareEntranceAnimation(
- () -> startAnimation(screenshot.getScreenBounds(), showFlash,
+ () -> startAnimation(animationBounds, showFlash,
() -> mMessageContainerController.onScreenshotTaken(screenshot)));
mViewProxy.setScreenshot(screenshot);
@@ -646,7 +641,7 @@
private void saveScreenshotInBackground(ScreenshotData screenshot, UUID requestId,
Consumer<Uri> finisher, Consumer<ImageExporter.Result> onResult) {
ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
- requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
+ requestId, screenshot.getBitmap(), screenshot.getUserHandle(),
mDisplay.getDisplayId());
future.addListener(() -> {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
index a762d84..f5c6052 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.kt
@@ -35,7 +35,6 @@
import android.view.Display
import android.view.ScrollCaptureResponse
import android.view.ViewRootImpl.ActivityConfigCallback
-import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import android.widget.Toast
import android.window.WindowContext
@@ -60,7 +59,6 @@
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.function.Consumer
-import javax.inject.Provider
import kotlin.math.abs
/** Controls the state and flow for screenshots. */
@@ -73,7 +71,7 @@
screenshotNotificationsControllerFactory: ScreenshotNotificationsController.Factory,
screenshotActionsControllerFactory: ScreenshotActionsController.Factory,
actionExecutorFactory: ActionExecutor.Factory,
- screenshotSoundControllerProvider: Provider<ScreenshotSoundController?>,
+ private val screenshotSoundController: ScreenshotSoundController,
private val uiEventLogger: UiEventLogger,
private val imageExporter: ImageExporter,
private val imageCapture: ImageCapture,
@@ -100,7 +98,6 @@
private val currentRequestCallbacks: MutableList<TakeScreenshotService.RequestCallback> =
mutableListOf()
- private var screenshotSoundController: ScreenshotSoundController? = null
private var screenBitmap: Bitmap? = null
private var screenshotTakenInPortrait = false
private var screenshotAnimation: Animator? = null
@@ -138,14 +135,6 @@
actionExecutor = actionExecutorFactory.create(window.window, viewProxy) { finishDismiss() }
actionsController = screenshotActionsControllerFactory.getController(actionExecutor)
- // Sound is only reproduced from the controller of the default display.
- screenshotSoundController =
- if (display.displayId == Display.DEFAULT_DISPLAY) {
- screenshotSoundControllerProvider.get()
- } else {
- null
- }
-
copyBroadcastReceiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -172,12 +161,6 @@
Assert.isMainThread()
screenshotHandler.resetTimeout()
- if (screenshot.type == TAKE_SCREENSHOT_FULLSCREEN && screenshot.bitmap == null) {
- val bounds = fullScreenRect
- screenshot.bitmap = imageCapture.captureDisplay(display.displayId, bounds)
- screenshot.screenBounds = bounds
- }
-
val currentBitmap = screenshot.bitmap
if (currentBitmap == null) {
Log.e(TAG, "handleScreenshot: Screenshot bitmap was null")
@@ -238,23 +221,27 @@
window.attachWindow()
+ var bounds =
+ screenshot.originalScreenBounds ?: Rect(0, 0, currentBitmap.width, currentBitmap.height)
+
val showFlash: Boolean
if (screenshot.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- if (aspectRatiosMatch(currentBitmap, screenshot.insets, screenshot.screenBounds)) {
+ if (
+ aspectRatiosMatch(
+ currentBitmap,
+ screenshot.originalInsets,
+ screenshot.originalScreenBounds,
+ )
+ ) {
showFlash = false
} else {
showFlash = true
- screenshot.insets = Insets.NONE
- screenshot.screenBounds = Rect(0, 0, currentBitmap.width, currentBitmap.height)
+ bounds = Rect(0, 0, currentBitmap.width, currentBitmap.height)
}
} else {
showFlash = true
}
- // screenshot.screenBounds is expected to be non-null in all cases at this point
- val bounds =
- screenshot.screenBounds ?: Rect(0, 0, currentBitmap.width, currentBitmap.height)
-
viewProxy.prepareEntranceAnimation {
startAnimation(bounds, showFlash) {
messageContainerController.onScreenshotTaken(screenshot)
@@ -305,7 +292,7 @@
// Any cleanup needed when the service is being destroyed.
override fun onDestroy() {
removeWindow()
- releaseMediaPlayer()
+ screenshotSoundController.releaseScreenshotSoundAsync()
releaseContext()
bgExecutor.shutdown()
}
@@ -316,10 +303,6 @@
context.release()
}
- private fun releaseMediaPlayer() {
- screenshotSoundController?.releaseScreenshotSoundAsync()
- }
-
/** Update resources on configuration change. Reinflate for theme/color changes. */
private fun reloadAssets() {
if (LogConfig.DEBUG_UI) {
@@ -445,18 +428,13 @@
viewProxy.stopInputListening()
}
- private fun playCameraSoundIfNeeded() {
- // the controller is not-null only on the default display controller
- screenshotSoundController?.playScreenshotSoundAsync()
- }
-
/**
* Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
* failure).
*/
private fun saveScreenshotAndToast(screenshot: ScreenshotData, finisher: Consumer<Uri?>) {
// Play the shutter sound to notify that we've taken a screenshot
- playCameraSoundIfNeeded()
+ screenshotSoundController.playScreenshotSoundAsync()
saveScreenshotInBackground(screenshot, UUID.randomUUID(), finisher) {
result: ImageExporter.Result ->
@@ -485,7 +463,7 @@
viewProxy.createScreenshotDropInAnimation(screenRect, showFlash).apply {
doOnEnd { onAnimationComplete?.run() }
// Play the shutter sound to notify that we've taken a screenshot
- playCameraSoundIfNeeded()
+ screenshotSoundController.playScreenshotSoundAsync()
if (LogConfig.DEBUG_ANIM) {
Log.d(TAG, "starting post-screenshot animation")
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
index 2df1e8a..b5b15a9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotData.kt
@@ -4,7 +4,6 @@
import android.graphics.Bitmap
import android.graphics.Insets
import android.graphics.Rect
-import android.os.Process
import android.os.UserHandle
import android.view.Display
import android.view.WindowManager
@@ -21,19 +20,15 @@
val userHandle: UserHandle,
/** ComponentName of the top-most app in the screenshot. */
val topComponent: ComponentName?,
- var screenBounds: Rect?,
val taskId: Int,
- var insets: Insets,
+ val originalScreenBounds: Rect?,
+ val originalInsets: Insets,
var bitmap: Bitmap?,
val displayId: Int,
) {
val packageNameString
get() = topComponent?.packageName ?: ""
- fun getUserOrDefault(): UserHandle {
- return userHandle ?: Process.myUserHandle()
- }
-
companion object {
@JvmStatic
fun fromRequest(request: ScreenshotRequest, displayId: Int = Display.DEFAULT_DISPLAY) =
@@ -42,9 +37,9 @@
source = request.source,
userHandle = UserHandle.of(request.userId),
topComponent = request.topComponent,
- screenBounds = request.boundsInScreen,
+ originalScreenBounds = request.boundsInScreen,
taskId = request.taskId,
- insets = request.insets,
+ originalInsets = request.insets,
bitmap = request.bitmap,
displayId = displayId,
)
@@ -61,9 +56,9 @@
source = source,
userHandle = userHandle,
topComponent = topComponent,
- screenBounds = null,
+ originalScreenBounds = null,
taskId = 0,
- insets = Insets.NONE,
+ originalInsets = Insets.NONE,
bitmap = bitmap,
displayId = Display.DEFAULT_DISPLAY,
)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
index b67ad8a..039143a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
@@ -126,7 +126,7 @@
)
}
- suspend fun replaceWithTaskSnapshot(
+ private suspend fun replaceWithTaskSnapshot(
original: ScreenshotData,
componentName: ComponentName?,
owner: UserHandle,
@@ -134,14 +134,14 @@
taskBounds: Rect?,
): ScreenshotData {
Log.i(TAG, "Capturing task snapshot: $componentName / $owner")
- val taskSnapshot = capture.captureTask(taskId)
+ val taskSnapshot = capture.captureTask(taskId) ?: error("Failed to capture task")
return original.copy(
type = TAKE_SCREENSHOT_PROVIDED_IMAGE,
bitmap = taskSnapshot,
userHandle = owner,
taskId = taskId,
topComponent = componentName,
- screenBounds = taskBounds,
+ originalScreenBounds = taskBounds,
)
}
@@ -153,13 +153,13 @@
taskId: Int? = null,
): ScreenshotData {
Log.i(TAG, "Capturing screenshot: $componentName / $owner")
- val screenshot = captureDisplay(displayId)
+ val screenshot = captureDisplay(displayId) ?: error("Failed to capture screenshot")
return original.copy(
type = TAKE_SCREENSHOT_FULLSCREEN,
bitmap = screenshot,
userHandle = owner,
topComponent = componentName,
- screenBounds = Rect(0, 0, screenshot?.width ?: 0, screenshot?.height ?: 0),
+ originalScreenBounds = Rect(0, 0, screenshot.width, screenshot.height),
taskId = taskId ?: -1,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2bff7c86..757e37e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2728,6 +2728,11 @@
}
private int calculatePanelHeightShade() {
+ // Bypass should always occupy the full height
+ if (mBarState == KEYGUARD && mKeyguardBypassController.getBypassEnabled()) {
+ return mNotificationStackScrollLayoutController.getHeight();
+ }
+
int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index fc8a593..5afc539 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -35,6 +35,7 @@
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -89,6 +90,7 @@
overlaysProvider: Provider<Set<@JvmSuppressWildcards Overlay>>,
layoutInsetController: NotificationInsetsController,
sceneDataSourceDelegator: Provider<SceneDataSourceDelegator>,
+ qsSceneAdapter: Provider<QSSceneAdapter>,
alternateBouncerDependencies: Provider<AlternateBouncerDependencies>,
): WindowRootView {
return if (SceneContainerFlag.isEnabled) {
@@ -104,6 +106,7 @@
overlays = overlaysProvider.get(),
layoutInsetController = layoutInsetController,
sceneDataSourceDelegator = sceneDataSourceDelegator.get(),
+ qsSceneAdapter = qsSceneAdapter,
alternateBouncerDependencies = alternateBouncerDependencies.get(),
)
sceneWindowRootView
@@ -119,9 +122,7 @@
// {@link NotificationShadeWindowViewController} can inject this view.
@Provides
@SysUISingleton
- fun providesNotificationShadeWindowView(
- root: WindowRootView,
- ): NotificationShadeWindowView {
+ fun providesNotificationShadeWindowView(root: WindowRootView): NotificationShadeWindowView {
if (SceneContainerFlag.isEnabled) {
return root.requireViewById(R.id.legacy_window_root)
}
@@ -133,7 +134,7 @@
@Provides
@SysUISingleton
fun providesNotificationStackScrollLayout(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): NotificationStackScrollLayout {
return notificationShadeWindowView.requireViewById(R.id.notification_stack_scroller)
}
@@ -142,7 +143,7 @@
@Provides
@SysUISingleton
fun providesNotificationPanelView(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): NotificationPanelView {
return notificationShadeWindowView.requireViewById(R.id.notification_panel)
}
@@ -178,7 +179,7 @@
@Provides
@SysUISingleton
fun providesKeyguardRootView(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): KeyguardRootView {
return notificationShadeWindowView.requireViewById(R.id.keyguard_root_view)
}
@@ -186,7 +187,7 @@
@Provides
@SysUISingleton
fun providesSharedNotificationContainer(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): SharedNotificationContainer {
return notificationShadeWindowView.requireViewById(R.id.shared_notification_container)
}
@@ -195,7 +196,7 @@
@Provides
@SysUISingleton
fun providesAuthRippleView(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): AuthRippleView? {
return notificationShadeWindowView.requireViewById(R.id.auth_ripple)
}
@@ -203,9 +204,7 @@
// TODO(b/277762009): Only allow this view's controller to inject the view. See above.
@Provides
@SysUISingleton
- fun providesTapAgainView(
- notificationPanelView: NotificationPanelView,
- ): TapAgainView {
+ fun providesTapAgainView(notificationPanelView: NotificationPanelView): TapAgainView {
return notificationPanelView.requireViewById(R.id.shade_falsing_tap_again)
}
@@ -213,7 +212,7 @@
@Provides
@SysUISingleton
fun providesNotificationsQuickSettingsContainer(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): NotificationsQuickSettingsContainer {
return notificationShadeWindowView.requireViewById(R.id.notification_container_parent)
}
@@ -223,7 +222,7 @@
@SysUISingleton
@Named(SHADE_HEADER)
fun providesShadeHeaderView(
- notificationShadeWindowView: NotificationShadeWindowView,
+ notificationShadeWindowView: NotificationShadeWindowView
): MotionLayout {
val stub = notificationShadeWindowView.requireViewById<ViewStub>(R.id.qs_header_stub)
val layoutId = R.layout.combined_qs_header
@@ -275,7 +274,7 @@
@SysUISingleton
@Named(SHADE_HEADER)
fun providesOngoingPrivacyChip(
- @Named(SHADE_HEADER) header: MotionLayout,
+ @Named(SHADE_HEADER) header: MotionLayout
): OngoingPrivacyChip {
return header.requireViewById(R.id.privacy_chip)
}
@@ -284,7 +283,7 @@
@SysUISingleton
@Named(SHADE_HEADER)
fun providesStatusIconContainer(
- @Named(SHADE_HEADER) header: MotionLayout,
+ @Named(SHADE_HEADER) header: MotionLayout
): StatusIconContainer {
return header.requireViewById(R.id.statusIcons)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 2c6b09c..adb3352 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3884,6 +3884,7 @@
}
showingLayout.dump(pw, args);
dumpCustomOutline(pw, args);
+ dumpClipping(pw, args);
if (getViewState() != null) {
getViewState().dump(pw, args);
pw.println();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index afda426..ef6cad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -856,17 +856,23 @@
pw.println();
}
if (DUMP_VERBOSE) {
- pw.println("mInRemovalAnimation: " + mInRemovalAnimation);
- pw.println("mClipTopAmount: " + mClipTopAmount);
- pw.println("mClipBottomAmount " + mClipBottomAmount);
- pw.println("mClipToActualHeight: " + mClipToActualHeight);
- pw.println("mExtraWidthForClipping: " + mExtraWidthForClipping);
- pw.println("mMinimumHeightForClipping: " + mMinimumHeightForClipping);
- pw.println("getClipBounds(): " + getClipBounds());
+ dumpClipping(pw, args);
}
});
}
+ protected void dumpClipping(IndentingPrintWriter pw, String[] args) {
+ pw.print("Clipping: ");
+ pw.print("mInRemovalAnimation", mInRemovalAnimation);
+ pw.print("mClipTopAmount", mClipTopAmount);
+ pw.print("mClipBottomAmount", mClipBottomAmount);
+ pw.print("mClipToActualHeight", mClipToActualHeight);
+ pw.print("mExtraWidthForClipping", mExtraWidthForClipping);
+ pw.print("mMinimumHeightForClipping", mMinimumHeightForClipping);
+ pw.print("getClipBounds()", getClipBounds());
+ pw.println();
+ }
+
/**
* return the amount that the content is translated
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 36e3e92..69f45db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -360,11 +360,11 @@
if ((contentViews & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
row.getPublicLayout().removeContentInactiveRunnable(VISIBLE_TYPE_CONTRACTED);
}
- if (AsyncHybridViewInflation.isEnabled()
+ if (LockscreenOtpRedaction.isEnabled()
&& (contentViews & FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE) != 0) {
row.getPublicLayout().removeContentInactiveRunnable(VISIBLE_TYPE_SINGLELINE);
}
- if (LockscreenOtpRedaction.isEnabled()
+ if (AsyncHybridViewInflation.isEnabled()
&& (contentViews & FLAG_CONTENT_VIEW_SINGLE_LINE) != 0) {
row.getPrivateLayout().removeContentInactiveRunnable(VISIBLE_TYPE_SINGLELINE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 8ae6b79..d828a67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -130,6 +130,7 @@
import com.android.systemui.util.ColorUtilKt;
import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.util.ListenerSet;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
import com.google.errorprone.annotations.CompileTimeConstant;
@@ -628,6 +629,9 @@
@Nullable
private OnClickListener mManageButtonClickListener;
+ @Nullable
+ private WallpaperInteractor mWallpaperInteractor;
+
public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -1192,6 +1196,7 @@
if (!SceneContainerFlag.isEnabled()) {
setMaxLayoutHeight(getHeight());
updateContentHeight();
+ mWallpaperInteractor.setNotificationStackAbsoluteBottom(mContentHeight);
}
clampScrollPosition();
requestChildrenUpdate();
@@ -1253,6 +1258,7 @@
if (mAmbientState.getStackTop() != stackTop) {
mAmbientState.setStackTop(stackTop);
onTopPaddingChanged(/* animate = */ isAddOrRemoveAnimationPending());
+ mWallpaperInteractor.setNotificationStackAbsoluteBottom((int) stackTop);
}
}
@@ -5898,6 +5904,10 @@
mController.getNotificationRoundnessManager().setAnimatedChildren(mChildrenToAddAnimated);
}
+ public void setWallpaperInteractor(WallpaperInteractor wallpaperInteractor) {
+ mWallpaperInteractor = wallpaperInteractor;
+ }
+
void addSwipedOutView(View v) {
mSwipedOutViews.add(v);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7b02d0c..00c5c40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -145,6 +145,7 @@
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Compile;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -226,6 +227,8 @@
private final SensitiveNotificationProtectionController
mSensitiveNotificationProtectionController;
+ private final WallpaperInteractor mWallpaperInteractor;
+
private View mLongPressedView;
private final NotificationListContainerImpl mNotificationListContainer =
@@ -756,7 +759,8 @@
NotificationDismissibilityProvider dismissibilityProvider,
ActivityStarter activityStarter,
SplitShadeStateController splitShadeStateController,
- SensitiveNotificationProtectionController sensitiveNotificationProtectionController) {
+ SensitiveNotificationProtectionController sensitiveNotificationProtectionController,
+ WallpaperInteractor wallpaperInteractor) {
mView = view;
mKeyguardTransitionRepo = keyguardTransitionRepo;
mViewBinder = viewBinder;
@@ -812,6 +816,7 @@
mDismissibilityProvider = dismissibilityProvider;
mActivityStarter = activityStarter;
mSensitiveNotificationProtectionController = sensitiveNotificationProtectionController;
+ mWallpaperInteractor = wallpaperInteractor;
mView.passSplitShadeStateController(splitShadeStateController);
if (SceneContainerFlag.isEnabled()) {
mWakeUpCoordinator.setStackScroller(this);
@@ -948,6 +953,8 @@
collectFlow(mView, mKeyguardTransitionRepo.getTransitions(),
this::onKeyguardTransitionChanged);
}
+
+ mView.setWallpaperInteractor(mWallpaperInteractor);
}
private boolean isInVisibleLocation(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 178c318..6a77988 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -182,14 +182,8 @@
mCarrierLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
- lp = (MarginLayoutParams) mCarrierLabel.getLayoutParams();
+ updateCarrierLabelMargin();
- int marginStart = calculateMargin(
- getResources().getDimensionPixelSize(R.dimen.keyguard_carrier_text_margin),
- mPadding.left);
- lp.setMarginStart(marginStart);
-
- mCarrierLabel.setLayoutParams(lp);
updateKeyguardStatusBarHeight();
}
@@ -203,6 +197,15 @@
setLayoutParams(lp);
}
+ private void updateCarrierLabelMargin() {
+ MarginLayoutParams lp = (MarginLayoutParams) mCarrierLabel.getLayoutParams();
+ int marginStart = calculateMargin(
+ getResources().getDimensionPixelSize(R.dimen.keyguard_carrier_text_margin),
+ mPadding.left);
+ lp.setMarginStart(marginStart);
+ mCarrierLabel.setLayoutParams(lp);
+ }
+
void loadDimens() {
Resources res = getResources();
mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize(
@@ -334,6 +337,7 @@
RelativeLayout.LayoutParams lp = (LayoutParams) mCarrierLabel.getLayoutParams();
lp.addRule(RelativeLayout.START_OF, R.id.status_icon_area);
+ updateCarrierLabelMargin();
lp = (LayoutParams) mStatusIconArea.getLayoutParams();
lp.removeRule(RelativeLayout.RIGHT_OF);
@@ -366,6 +370,7 @@
lp = (LayoutParams) mCarrierLabel.getLayoutParams();
lp.addRule(RelativeLayout.START_OF, R.id.cutout_space_view);
+ updateCarrierLabelMargin();
lp = (LayoutParams) mStatusIconArea.getLayoutParams();
lp.addRule(RelativeLayout.RIGHT_OF, R.id.cutout_space_view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index e09e577..0cba940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Flags.registerZenModeContentObserverBackground;
-
import android.app.AlarmManager;
import android.app.Flags;
import android.app.NotificationManager;
@@ -47,7 +45,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.settings.UserTracker;
@@ -107,7 +104,6 @@
public ZenModeControllerImpl(
Context context,
@Main Handler handler,
- @Background Handler bgHandler,
BroadcastDispatcher broadcastDispatcher,
DumpManager dumpManager,
GlobalSettings globalSettings,
@@ -138,17 +134,9 @@
}
};
mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- if (registerZenModeContentObserverBackground()) {
- bgHandler.post(() -> {
- globalSettings.registerContentObserverSync(Global.ZEN_MODE, modeContentObserver);
- globalSettings.registerContentObserverSync(Global.ZEN_MODE_CONFIG_ETAG,
- configContentObserver);
- });
- } else {
- globalSettings.registerContentObserverSync(Global.ZEN_MODE, modeContentObserver);
- globalSettings.registerContentObserverSync(Global.ZEN_MODE_CONFIG_ETAG,
- configContentObserver);
- }
+ globalSettings.registerContentObserverAsync(Global.ZEN_MODE, modeContentObserver);
+ globalSettings.registerContentObserverAsync(Global.ZEN_MODE_CONFIG_ETAG,
+ configContentObserver);
updateZenMode(getModeSettingValueFromProvider());
updateZenModeConfig();
updateConsolidatedNotificationPolicy();
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
index 8957fe1..09cef1e 100644
--- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
@@ -18,6 +18,7 @@
package com.android.systemui.user.legacyhelper.ui
import android.content.Context
+import android.util.Log
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.android.systemui.res.R
@@ -32,6 +33,8 @@
*/
object LegacyUserUiHelper {
+ private const val TAG = "LegacyUserUiHelper"
+
@JvmStatic
@DrawableRes
fun getUserSwitcherActionIconResourceId(
@@ -67,7 +70,9 @@
val resourceId: Int? = getGuestUserRecordNameResourceId(record)
return when {
resourceId != null -> context.getString(resourceId)
- record.info != null -> checkNotNull(record.info.name)
+ record.info != null ->
+ record.info.name
+ ?: "".also { Log.i(TAG, "Expected display name for: ${record.info}") }
else ->
context.getString(
getUserSwitcherActionTextResourceId(
diff --git a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
index 947746c..4b2fe49 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AlphaTintDrawableWrapper.java
@@ -45,8 +45,8 @@
* This class should only be used in XML.
*
* @attr ref android.R.styleable#DrawableWrapper_drawable
- * @attr ref R.styleable#AlphaTintDrawableWrapper_tint
- * @attr ref R.styleable#AlphaTintDrawableWrapper_alpha
+ * @attr ref android.R.styleable#AlphaTintDrawableWrapper_tint
+ * @attr ref android.R.styleable#AlphaTintDrawableWrapper_alpha
*/
public class AlphaTintDrawableWrapper extends InsetDrawable {
private ColorStateList mTint;
diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
index 65a0218..0744b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
@@ -32,19 +32,24 @@
* Note: New logic should be added to [WallpaperRepository], not this class.
*/
@SysUISingleton
-class WallpaperController @Inject constructor(
+class WallpaperController
+@Inject
+constructor(
private val wallpaperManager: WallpaperManager,
private val wallpaperRepository: WallpaperRepository,
) {
var rootView: View? = null
+ set(value) {
+ field = value
+ wallpaperRepository.rootView = value
+ }
private var notificationShadeZoomOut: Float = 0f
private var unfoldTransitionZoomOut: Float = 0f
private val shouldUseDefaultUnfoldTransition: Boolean
- get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition()
- ?: true
+ get() = wallpaperRepository.wallpaperInfo.value?.shouldUseDefaultUnfoldTransition() ?: true
fun setNotificationShadeZoom(zoomOut: Float) {
notificationShadeZoomOut = zoomOut
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
index b45b8cd..54953c9 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.wallpapers.data.repository
import android.app.WallpaperInfo
+import android.view.View
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
@@ -33,4 +34,7 @@
class NoopWallpaperRepository @Inject constructor() : WallpaperRepository {
override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow()
override val wallpaperSupportsAmbientMode = MutableStateFlow(false).asStateFlow()
+ override var rootView: View? = null
+
+ override fun setNotificationStackAbsoluteBottom(bottom: Float) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
index 041b6f9..203e1da 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
@@ -21,10 +21,16 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.os.Bundle
import android.os.UserHandle
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
@@ -32,16 +38,19 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/** A repository storing information about the current wallpaper. */
@@ -51,6 +60,15 @@
/** Emits true if the current user's current wallpaper supports ambient mode. */
val wallpaperSupportsAmbientMode: StateFlow<Boolean>
+
+ /** Set rootView to get its windowToken afterwards */
+ var rootView: View?
+
+ /**
+ * Set bottom of notifications from notification stack, and Magic Portrait will layout base on
+ * this value
+ */
+ fun setNotificationStackAbsoluteBottom(bottom: Float)
}
@SysUISingleton
@@ -61,6 +79,8 @@
@Background private val bgDispatcher: CoroutineDispatcher,
broadcastDispatcher: BroadcastDispatcher,
userRepository: UserRepository,
+ keyguardRepository: KeyguardRepository,
+ keyguardClockRepository: KeyguardClockRepository,
private val wallpaperManager: WallpaperManager,
context: Context,
) : WallpaperRepository {
@@ -69,10 +89,7 @@
private val wallpaperChanged: Flow<Unit> =
broadcastDispatcher
- .broadcastFlow(
- IntentFilter(Intent.ACTION_WALLPAPER_CHANGED),
- user = UserHandle.ALL,
- )
+ .broadcastFlow(IntentFilter(Intent.ACTION_WALLPAPER_CHANGED), user = UserHandle.ALL)
// The `combine` defining `wallpaperSupportsAmbientMode` will not run until both of the
// input flows emit at least once. Since this flow is an input flow, it needs to emit
// when it starts up to ensure that the `combine` will run if the user changes before we
@@ -87,6 +104,27 @@
// Only update the wallpaper status once the user selection has finished.
.filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE }
+ /** The bottom of notification stack respect to the top of screen. */
+ private val notificationStackAbsoluteBottom: MutableStateFlow<Float> = MutableStateFlow(0F)
+
+ /** The top of shortcut respect to the top of screen. */
+ private val shortcutAbsoluteTop: StateFlow<Float> = keyguardRepository.shortcutAbsoluteTop
+
+ /**
+ * The top of notification stack to give a default state of lockscreen remaining space for
+ * states with notifications to compare with. It's the bottom of smartspace date and weather
+ * smartspace in small clock state, plus proper bottom margin.
+ */
+ private val notificationStackDefaultTop = keyguardClockRepository.notificationDefaultTop
+ @VisibleForTesting var sendLockscreenLayoutJob: Job? = null
+ private val lockscreenRemainingSpaceWithNotification: Flow<Triple<Float, Float, Float>> =
+ combine(
+ notificationStackAbsoluteBottom,
+ notificationStackDefaultTop,
+ shortcutAbsoluteTop,
+ ::Triple,
+ )
+
override val wallpaperInfo: StateFlow<WallpaperInfo?> =
if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) {
MutableStateFlow(null).asStateFlow()
@@ -116,9 +154,70 @@
initialValue = wallpaperInfo.value?.supportsAmbientMode() == true,
)
+ override var rootView: View? = null
+
+ val shouldSendNotificationLayout =
+ wallpaperInfo
+ .map {
+ val shouldSendNotificationLayout = shouldSendNotificationLayout(it)
+ if (shouldSendNotificationLayout) {
+ sendLockscreenLayoutJob =
+ scope.launch {
+ lockscreenRemainingSpaceWithNotification.collect {
+ (notificationBottom, notificationDefaultTop, shortcutTop) ->
+ wallpaperManager.sendWallpaperCommand(
+ /* windowToken = */ rootView?.windowToken,
+ /* action = */ WallpaperManager
+ .COMMAND_LOCKSCREEN_LAYOUT_CHANGED,
+ /* x = */ 0,
+ /* y = */ 0,
+ /* z = */ 0,
+ /* extras = */ Bundle().apply {
+ putFloat("screenLeft", 0F)
+ putFloat("smartspaceBottom", notificationDefaultTop)
+ putFloat("notificationBottom", notificationBottom)
+ putFloat(
+ "screenRight",
+ context.resources.displayMetrics.widthPixels.toFloat(),
+ )
+ putFloat("shortCutTop", shortcutTop)
+ },
+ )
+ }
+ }
+ } else {
+ sendLockscreenLayoutJob?.cancel()
+ }
+ shouldSendNotificationLayout
+ }
+ .stateIn(
+ scope,
+ // Always be listening for wallpaper changes.
+ if (Flags.magicPortraitWallpapers()) SharingStarted.Eagerly
+ else SharingStarted.Lazily,
+ initialValue = false,
+ )
+
+ override fun setNotificationStackAbsoluteBottom(bottom: Float) {
+ notificationStackAbsoluteBottom.value = bottom
+ }
+
private suspend fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? {
return withContext(bgDispatcher) {
wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id)
}
}
+
+ private fun shouldSendNotificationLayout(wallpaperInfo: WallpaperInfo?): Boolean {
+ return if (wallpaperInfo != null && wallpaperInfo.component != null) {
+ wallpaperInfo.component!!.className == MAGIC_PORTRAIT_CLASSNAME
+ } else {
+ false
+ }
+ }
+
+ companion object {
+ const val MAGIC_PORTRAIT_CLASSNAME =
+ "com.google.android.apps.magicportrait.service.MagicPortraitWallpaperService"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt
new file mode 100644
index 0000000..79ebf01
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.wallpapers.domain.interactor
+
+import com.android.systemui.wallpapers.data.repository.WallpaperRepository
+import javax.inject.Inject
+
+class WallpaperInteractor @Inject constructor(val wallpaperRepository: WallpaperRepository) {
+ fun setNotificationStackAbsoluteBottom(bottom: Float) {
+ wallpaperRepository.setNotificationStackAbsoluteBottom(bottom)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
new file mode 100644
index 0000000..5d5c120
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 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.display.data.repository
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.unconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DisplayScopeRepositoryImplTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher }
+ private val testScope = kosmos.testScope
+ private val fakeDisplayRepository = kosmos.displayRepository
+
+ private val repo =
+ DisplayScopeRepositoryImpl(
+ kosmos.applicationCoroutineScope,
+ kosmos.testDispatcher,
+ fakeDisplayRepository,
+ )
+
+ @Before
+ fun setUp() {
+ repo.start()
+ }
+
+ @Test
+ fun scopeForDisplay_multipleCallsForSameDisplayId_returnsSameInstance() {
+ val scopeForDisplay = repo.scopeForDisplay(displayId = 1)
+
+ assertThat(repo.scopeForDisplay(displayId = 1)).isSameInstanceAs(scopeForDisplay)
+ }
+
+ @Test
+ fun scopeForDisplay_differentDisplayId_returnsNewInstance() {
+ val scopeForDisplay1 = repo.scopeForDisplay(displayId = 1)
+ val scopeForDisplay2 = repo.scopeForDisplay(displayId = 2)
+
+ assertThat(scopeForDisplay1).isNotSameInstanceAs(scopeForDisplay2)
+ }
+
+ @Test
+ fun scopeForDisplay_activeByDefault() =
+ testScope.runTest {
+ val scopeForDisplay = repo.scopeForDisplay(displayId = 1)
+
+ assertThat(scopeForDisplay.isActive).isTrue()
+ }
+
+ @Test
+ fun scopeForDisplay_afterDisplayRemoved_scopeIsCancelled() =
+ testScope.runTest {
+ val scopeForDisplay = repo.scopeForDisplay(displayId = 1)
+
+ fakeDisplayRepository.removeDisplay(displayId = 1)
+
+ assertThat(scopeForDisplay.isActive).isFalse()
+ }
+
+ @Test
+ fun scopeForDisplay_afterDisplayRemoved_returnsNewInstance() =
+ testScope.runTest {
+ val initialScope = repo.scopeForDisplay(displayId = 1)
+
+ fakeDisplayRepository.removeDisplay(displayId = 1)
+
+ val newScope = repo.scopeForDisplay(displayId = 1)
+ assertThat(newScope).isNotSameInstanceAs(initialScope)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index 0b944f0..96a0aad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -39,13 +39,13 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
+import com.android.systemui.shade.LargeScreenHeaderHelper
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.policy.fakeConfigurationController
import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -57,6 +57,7 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@@ -122,6 +123,7 @@
{ keyguardBlueprintInteractor },
keyguardRootViewModel,
aodBurnInViewModel,
+ largeScreenHeaderHelperLazy = { mock<LargeScreenHeaderHelper>() },
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
index 1d74e8b..4ede90e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
@@ -53,8 +53,8 @@
assertThat(data.source).isEqualTo(source)
assertThat(data.type).isEqualTo(type)
- assertThat(data.screenBounds).isEqualTo(bounds)
- assertThat(data.insets).isEqualTo(insets)
+ assertThat(data.originalScreenBounds).isEqualTo(bounds)
+ assertThat(data.originalInsets).isEqualTo(insets)
assertThat(data.taskId).isEqualTo(taskId)
assertThat(data.userHandle).isEqualTo(UserHandle.of(userId))
assertThat(data.topComponent).isEqualTo(component)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
index 2fcacb9..0d4cb4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.screenshot.policy
import android.content.ComponentName
+import android.graphics.Bitmap
import android.graphics.Insets
import android.graphics.Rect
import android.os.UserHandle
@@ -27,10 +28,12 @@
import com.android.systemui.screenshot.ScreenshotData
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.FILES
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.TaskSpec
+import com.android.systemui.screenshot.data.model.DisplayContentScenarios.launcherOnly
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.singleFullScreen
import com.android.systemui.screenshot.data.repository.DisplayContentRepository
import com.android.systemui.screenshot.policy.TestUserIds.PERSONAL
import com.android.systemui.screenshot.policy.TestUserIds.WORK
+import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
@@ -39,14 +42,6 @@
@RunWith(AndroidJUnit4::class)
class PolicyRequestProcessorTest {
-
- val imageCapture =
- object : ImageCapture {
- override fun captureDisplay(displayId: Int, crop: Rect?) = null
-
- override suspend fun captureTask(taskId: Int) = null
- }
-
/** Tests behavior when no policies are applied */
@Test
fun testProcess_defaultOwner_whenNoPolicyApplied() {
@@ -60,9 +55,9 @@
SCREENSHOT_KEY_CHORD,
UserHandle.CURRENT,
topComponent = null,
- screenBounds = Rect(0, 0, 1, 1),
+ originalScreenBounds = Rect(0, 0, 1, 1),
taskId = -1,
- insets = Insets.NONE,
+ originalInsets = Insets.NONE,
bitmap = null,
displayId = DEFAULT_DISPLAY,
)
@@ -71,7 +66,7 @@
val requestProcessor =
PolicyRequestProcessor(
Dispatchers.Unconfined,
- imageCapture,
+ createImageCapture(),
policies = emptyList(),
defaultOwner = UserHandle.of(PERSONAL),
defaultComponent = ComponentName("default", "Component"),
@@ -91,6 +86,70 @@
assertWithMessage("Task ID").that(result.taskId).isEqualTo(TASK_ID)
}
+ @Test
+ fun testProcess_throwsWhenCaptureFails() {
+ val request = ScreenshotData.forTesting()
+
+ /* Create a policy request processor with no capture policies */
+ val requestProcessor =
+ PolicyRequestProcessor(
+ Dispatchers.Unconfined,
+ createImageCapture(display = null),
+ policies = emptyList(),
+ defaultComponent = ComponentName("default", "Component"),
+ displayTasks = DisplayContentRepository { launcherOnly() },
+ )
+
+ val result = runCatching { runBlocking { requestProcessor.process(request) } }
+
+ assertThat(result.isFailure).isTrue()
+ }
+
+ @Test
+ fun testProcess_throwsWhenTaskCaptureFails() {
+ val request = ScreenshotData.forTesting()
+ val fullScreenWork = DisplayContentRepository {
+ singleFullScreen(TaskSpec(taskId = TASK_ID, name = FILES, userId = WORK))
+ }
+
+ val captureTaskPolicy = CapturePolicy {
+ CapturePolicy.PolicyResult.Matched(
+ policy = "",
+ reason = "",
+ parameters =
+ CaptureParameters(
+ CaptureType.IsolatedTask(taskId = 0, taskBounds = null),
+ null,
+ UserHandle.CURRENT,
+ ),
+ )
+ }
+
+ /* Create a policy request processor with no capture policies */
+ val requestProcessor =
+ PolicyRequestProcessor(
+ Dispatchers.Unconfined,
+ createImageCapture(task = null),
+ policies = listOf(captureTaskPolicy),
+ defaultComponent = ComponentName("default", "Component"),
+ displayTasks = fullScreenWork,
+ )
+
+ val result = runCatching { runBlocking { requestProcessor.process(request) } }
+
+ assertThat(result.isFailure).isTrue()
+ }
+
+ private fun createImageCapture(
+ display: Bitmap? = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888),
+ task: Bitmap? = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888),
+ ) =
+ object : ImageCapture {
+ override fun captureDisplay(displayId: Int, crop: Rect?) = display
+
+ override suspend fun captureTask(taskId: Int) = task
+ }
+
companion object {
const val TASK_ID = 1001
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 7cd306e..6425da4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -83,6 +83,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -103,7 +104,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -113,6 +113,7 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
import org.junit.Before;
import org.junit.Test;
@@ -154,6 +155,7 @@
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private PowerInteractor mPowerInteractor;
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+ @Mock private WallpaperInteractor mWallpaperInteractor;
@Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock private MetricsLogger mMetricsLogger;
@Mock private ColorUpdateLogger mColorUpdateLogger;
@@ -1070,7 +1072,8 @@
mock(NotificationDismissibilityProvider.class),
mActivityStarter,
new ResourcesSplitShadeStateController(),
- mSensitiveNotificationProtectionController);
+ mSensitiveNotificationProtectionController,
+ mWallpaperInteractor);
}
static class LogMatcher implements ArgumentMatcher<LogMaker> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 8a3e551..59fc0d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -102,6 +102,7 @@
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.AvalancheController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
import kotlin.Unit;
@@ -146,6 +147,7 @@
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private NotificationShelf mNotificationShelf;
+ @Mock private WallpaperInteractor mWallpaperInteractor;
@Mock private NotificationStackSizeCalculator mStackSizeCalculator;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
@@ -208,6 +210,7 @@
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
mStackScroller.setShelf(mNotificationShelf);
+ mStackScroller.setWallpaperInteractor(mWallpaperInteractor);
when(mStackScroller.getExpandHelper()).thenReturn(mExpandHelper);
doNothing().when(mGroupExpansionManager).collapseGroups();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
deleted file mode 100644
index 637a0f1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 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.policy;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.NotificationManager;
-import android.os.Handler;
-import android.provider.Settings;
-import android.service.notification.ZenModeConfig;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.policy.ZenModeController.Callback;
-import com.android.systemui.util.settings.FakeGlobalSettings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@RunWithLooper
-public class ZenModeControllerImplTest extends SysuiTestCase {
-
- private Callback mCallback;
- @Mock
- NotificationManager mNm;
- @Mock
- ZenModeConfig mConfig;
- @Mock
- BroadcastDispatcher mBroadcastDispatcher;
- @Mock
- DumpManager mDumpManager;
- @Mock
- UserTracker mUserTracker;
- private ZenModeControllerImpl mController;
-
- private final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext.addMockSystemService(NotificationManager.class, mNm);
- when(mNm.getZenModeConfig()).thenReturn(mConfig);
-
- mController = new ZenModeControllerImpl(
- mContext,
- Handler.createAsync(TestableLooper.get(this).getLooper()),
- Handler.createAsync(TestableLooper.get(this).getLooper()),
- mBroadcastDispatcher,
- mDumpManager,
- mGlobalSettings,
- mUserTracker);
- }
-
- @Test
- public void testRemoveDuringCallback() {
- mCallback = new Callback() {
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- mController.removeCallback(mCallback);
- }
- };
- mController.addCallback(mCallback);
- Callback mockCallback = mock(Callback.class);
- mController.addCallback(mockCallback);
- mController.fireConfigChanged(null);
- verify(mockCallback).onConfigChanged(eq(null));
- }
-
- @Test
- public void testAreNotificationsHiddenInShade_zenOffShadeSuppressed() {
- mConfig.suppressedVisualEffects =
- NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
- mController.updateZenMode(Settings.Global.ZEN_MODE_OFF);
- mController.updateZenModeConfig();
-
- assertFalse(mController.areNotificationsHiddenInShade());
- }
-
- @Test
- public void testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
- NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
- NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR);
- when(mNm.getConsolidatedNotificationPolicy()).thenReturn(policy);
- mController.updateConsolidatedNotificationPolicy();
- mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-
- assertFalse(mController.areNotificationsHiddenInShade());
- }
-
- @Test
- public void testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
- NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
- NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST);
- when(mNm.getConsolidatedNotificationPolicy()).thenReturn(policy);
- mController.updateConsolidatedNotificationPolicy();
- mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-
- assertTrue(mController.areNotificationsHiddenInShade());
- }
-
- @Test
- public void testModeChange() {
- List<Integer> states = List.of(
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
- Settings.Global.ZEN_MODE_ALARMS,
- Settings.Global.ZEN_MODE_ALARMS
- );
-
- for (Integer state : states) {
- mGlobalSettings.putInt(Settings.Global.ZEN_MODE, state);
- TestableLooper.get(this).processAllMessages();
- assertEquals(state.intValue(), mController.getZen());
- }
- }
-
- @Test
- public void testModeChange_callbackNotified() {
- final AtomicInteger currentState = new AtomicInteger(-1);
-
- ZenModeController.Callback callback = new Callback() {
- @Override
- public void onZenChanged(int zen) {
- currentState.set(zen);
- }
- };
-
- mController.addCallback(callback);
-
- List<Integer> states = List.of(
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- Settings.Global.ZEN_MODE_NO_INTERRUPTIONS,
- Settings.Global.ZEN_MODE_ALARMS,
- Settings.Global.ZEN_MODE_ALARMS
- );
-
- for (Integer state : states) {
- mGlobalSettings.putInt(Settings.Global.ZEN_MODE, state);
- TestableLooper.get(this).processAllMessages();
- assertEquals(state.intValue(), currentState.get());
- }
-
- }
-
- @Test
- public void testCallbackRemovedWhileDispatching_doesntCrash() {
- final AtomicBoolean remove = new AtomicBoolean(false);
- mGlobalSettings.putInt(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- TestableLooper.get(this).processAllMessages();
- final ZenModeController.Callback callback = new ZenModeController.Callback() {
- @Override
- public void onZenChanged(int zen) {
- if (remove.get()) {
- mController.removeCallback(this);
- }
- }
- };
- mController.addCallback(callback);
- mController.addCallback(new ZenModeController.Callback() {});
-
- remove.set(true);
-
- mGlobalSettings.putInt(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
- TestableLooper.get(this).processAllMessages();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
index bdecf2b..b8dd334 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
@@ -18,18 +18,21 @@
import android.app.WallpaperInfo
import android.app.WallpaperManager
+import android.content.ComponentName
import android.content.Intent
import android.content.pm.UserInfo
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.wallpapers.data.repository.WallpaperRepositoryImpl.Companion.MAGIC_PORTRAIT_CLASSNAME
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -39,6 +42,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
@@ -48,6 +54,8 @@
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
private val userRepository = FakeUserRepository()
+ private val keyguardClockRepository = FakeKeyguardClockRepository()
+ private val keyguardRepository = FakeKeyguardRepository()
private val wallpaperManager: WallpaperManager = mock()
private val underTest: WallpaperRepositoryImpl by lazy {
@@ -56,6 +64,8 @@
testDispatcher,
fakeBroadcastDispatcher,
userRepository,
+ keyguardRepository,
+ keyguardClockRepository,
wallpaperManager,
context,
)
@@ -219,7 +229,7 @@
testScope.runTest {
context.orCreateTestableResources.addOverride(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper,
- false
+ false,
)
val latest by collectLastValue(underTest.wallpaperInfo)
@@ -407,7 +417,7 @@
testScope.runTest {
context.orCreateTestableResources.addOverride(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper,
- false
+ false,
)
val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode)
@@ -425,6 +435,54 @@
assertThat(latest).isFalse()
}
+ @Test
+ @EnableFlags(Flags.FLAG_MAGIC_PORTRAIT_WALLPAPERS)
+ fun shouldSendNotificationLayout_setMagicPortraitWallpaper_launchSendLayoutJob() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.shouldSendNotificationLayout)
+ val magicPortraitWallpaper =
+ mock<WallpaperInfo>().apply {
+ whenever(this.component)
+ .thenReturn(ComponentName(context, MAGIC_PORTRAIT_CLASSNAME))
+ }
+ whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+ .thenReturn(magicPortraitWallpaper)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(Intent.ACTION_WALLPAPER_CHANGED),
+ )
+ assertThat(latest).isTrue()
+ assertThat(underTest.sendLockscreenLayoutJob).isNotNull()
+ assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MAGIC_PORTRAIT_WALLPAPERS)
+ fun shouldSendNotificationLayout_setNotMagicPortraitWallpaper_cancelSendLayoutJob() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.shouldSendNotificationLayout)
+ val magicPortraitWallpaper = MAGIC_PORTRAIT_WP
+ whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+ .thenReturn(magicPortraitWallpaper)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(Intent.ACTION_WALLPAPER_CHANGED),
+ )
+ assertThat(latest).isTrue()
+ assertThat(underTest.sendLockscreenLayoutJob).isNotNull()
+ assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true)
+
+ val nonMagicPortraitWallpaper = UNSUPPORTED_WP
+ whenever(wallpaperManager.getWallpaperInfoForUser(any()))
+ .thenReturn(nonMagicPortraitWallpaper)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(Intent.ACTION_WALLPAPER_CHANGED),
+ )
+ assertThat(latest).isFalse()
+ assertThat(underTest.sendLockscreenLayoutJob?.isCancelled).isEqualTo(true)
+ }
+
private companion object {
val USER_WITH_UNSUPPORTED_WP = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0)
val UNSUPPORTED_WP =
@@ -433,5 +491,10 @@
val USER_WITH_SUPPORTED_WP = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0)
val SUPPORTED_WP =
mock<WallpaperInfo>().apply { whenever(this.supportsAmbientMode()).thenReturn(true) }
+
+ val MAGIC_PORTRAIT_WP =
+ mock<WallpaperInfo>().apply {
+ whenever(this.component).thenReturn(ComponentName("", MAGIC_PORTRAIT_CLASSNAME))
+ }
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
new file mode 100644
index 0000000..2850ab7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.app
+
+import android.app.WallpaperManager
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.wallpaperManager: WallpaperManager by Fixture {
+ WallpaperManager.getInstance(applicationContext)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index 6c3cf91..fcc83b3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -24,16 +24,12 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import org.mockito.Mockito.`when` as whenever
/** Creates a mock display. */
-fun display(
- type: Int,
- flags: Int = 0,
- id: Int = 0,
- state: Int? = null,
-): Display {
+fun display(type: Int, flags: Int = 0, id: Int = 0, state: Int? = null): Display {
return mock {
whenever(this.displayId).thenReturn(id)
whenever(this.type).thenReturn(type)
@@ -51,10 +47,21 @@
@SysUISingleton
/** Fake [DisplayRepository] implementation for testing. */
class FakeDisplayRepository @Inject constructor() : DisplayRepository {
- private val flow = MutableSharedFlow<Set<Display>>(replay = 1)
+ private val flow = MutableStateFlow<Set<Display>>(emptySet())
private val pendingDisplayFlow =
MutableSharedFlow<DisplayRepository.PendingDisplay?>(replay = 1)
- private val displayAdditionEventFlow = MutableSharedFlow<Display?>(replay = 1)
+ private val displayAdditionEventFlow = MutableSharedFlow<Display?>(replay = 0)
+ private val displayRemovalEventFlow = MutableSharedFlow<Int>(replay = 0)
+
+ suspend fun addDisplay(display: Display) {
+ flow.value += display
+ displayAdditionEventFlow.emit(display)
+ }
+
+ suspend fun removeDisplay(displayId: Int) {
+ flow.value = flow.value.filter { it.displayId != displayId }.toSet()
+ displayRemovalEventFlow.emit(displayId)
+ }
/** Emits [value] as [displayAdditionEvent] flow value. */
suspend fun emit(value: Display?) = displayAdditionEventFlow.emit(value)
@@ -65,7 +72,7 @@
/** Emits [value] as [pendingDisplay] flow value. */
suspend fun emit(value: DisplayRepository.PendingDisplay?) = pendingDisplayFlow.emit(value)
- override val displays: Flow<Set<Display>>
+ override val displays: StateFlow<Set<Display>>
get() = flow
override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?>
@@ -78,8 +85,11 @@
override val displayAdditionEvent: Flow<Display?>
get() = displayAdditionEventFlow
+ override val displayRemovalEvent: Flow<Int> = displayRemovalEventFlow
+
private val _displayChangeEvent = MutableSharedFlow<Int>(replay = 1)
override val displayChangeEvent: Flow<Int> = _displayChangeEvent
+
suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId)
fun setDefaultDisplayOff(defaultDisplayOff: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 5e5f8cb..159dd34 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -46,16 +46,27 @@
private val _previewClock = MutableStateFlow(Mockito.mock(ClockController::class.java))
override val previewClock: Flow<ClockController>
get() = _previewClock
+
+ private val _notificationDefaultTop = MutableStateFlow(0F)
+ override val notificationDefaultTop: StateFlow<Float>
+ get() = _notificationDefaultTop
+
override val clockEventController: ClockEventController
get() = mock()
+
override val shouldForceSmallClock: Boolean
get() = _shouldForceSmallClock
+
private var _shouldForceSmallClock: Boolean = false
override fun setClockSize(size: ClockSize) {
_clockSize.value = size
}
+ override fun setNotificationDefaultTop(top: Float) {
+ _notificationDefaultTop.value = top
+ }
+
fun setSelectedClockSize(size: ClockSizeSetting) {
_selectedClockSize.value = size
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 54a6c0c..e513e8d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -131,6 +131,10 @@
private val _isEncryptedOrLockdown = MutableStateFlow(true)
override val isEncryptedOrLockdown: Flow<Boolean> = _isEncryptedOrLockdown
+ private val _shortcutAbsoluteTop = MutableStateFlow(0F)
+ override val shortcutAbsoluteTop: StateFlow<Float>
+ get() = _shortcutAbsoluteTop.asStateFlow()
+
private val _isKeyguardEnabled = MutableStateFlow(true)
override val isKeyguardEnabled: StateFlow<Boolean> = _isKeyguardEnabled.asStateFlow()
@@ -241,7 +245,7 @@
override fun setBiometricUnlockState(
mode: BiometricUnlockMode,
- source: BiometricUnlockSource?
+ source: BiometricUnlockSource?,
) {
_biometricUnlockState.tryEmit(BiometricUnlockModel(mode, source))
}
@@ -294,6 +298,10 @@
return isShowKeyguardWhenReenabled
}
+ override fun setShortcutAbsoluteTop(top: Float) {
+ _shortcutAbsoluteTop.value = top
+ }
+
override fun setCanIgnoreAuthAndReturnToGone(canWake: Boolean) {
_canIgnoreAuthAndReturnToGone.value = canWake
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
index 12d7c49..49a8c18 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
@@ -29,9 +29,10 @@
import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.shade.LargeScreenHeaderHelper
import java.util.Optional
import org.mockito.Mockito.spy
+import org.mockito.kotlin.mock
val Kosmos.keyguardClockSection: ClockSection by
Kosmos.Fixture {
@@ -43,6 +44,7 @@
blueprintInteractor = { keyguardBlueprintInteractor },
rootViewModel = keyguardRootViewModel,
aodBurnInViewModel = aodBurnInViewModel,
+ largeScreenHeaderHelperLazy = { mock<LargeScreenHeaderHelper>() },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
index d52883e..bdb9abb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
@@ -27,13 +27,13 @@
val Kosmos.keyguardClockInteractor by
Kosmos.Fixture {
KeyguardClockInteractor(
- keyguardClockRepository = keyguardClockRepository,
- applicationScope = applicationCoroutineScope,
mediaCarouselInteractor = mediaCarouselInteractor,
activeNotificationsInteractor = activeNotificationsInteractor,
shadeInteractor = shadeInteractor,
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
headsUpNotificationInteractor = headsUpNotificationInteractor,
+ applicationScope = applicationCoroutineScope,
+ keyguardClockRepository = keyguardClockRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
new file mode 100644
index 0000000..1d8c891
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.wallpapers.data.repository
+
+import android.content.applicationContext
+import com.android.app.wallpaperManager
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.keyguard.data.repository.keyguardClockRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.user.data.repository.userRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.wallpaperRepository by Fixture {
+ WallpaperRepositoryImpl(
+ context = applicationContext,
+ scope = testScope,
+ bgDispatcher = testDispatcher,
+ broadcastDispatcher = broadcastDispatcher,
+ userRepository = userRepository,
+ wallpaperManager = wallpaperManager,
+ keyguardClockRepository = keyguardClockRepository,
+ keyguardRepository = keyguardRepository,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt
new file mode 100644
index 0000000..5278351
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractorKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.wallpapers.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.wallpapers.data.repository.wallpaperRepository
+
+val Kosmos.wallpaperInteractor by
+ Kosmos.Fixture { WallpaperInteractor(wallpaperRepository = wallpaperRepository) }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 42f69e9..95281c8 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -676,7 +676,7 @@
final MacAddress macAddressObj = MacAddress.fromString(macAddress);
mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddressObj,
- null, null, null, false, null, null);
+ null, null, null, false, null, null, null);
}
private void checkCanCallNotificationApi(String callingPackage, int userId) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 4fc9d55..2804945 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -106,8 +106,8 @@
boolean selfManaged = getNextBooleanArg();
final MacAddress macAddress = MacAddress.fromString(address);
mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddress,
- deviceProfile, deviceProfile, /* associatedDevice */ null, selfManaged,
- /* callback */ null, /* resultReceiver */ null);
+ deviceProfile, deviceProfile, /* associatedDevice */ null, false,
+ /* callback */ null, /* resultReceiver */ null, /* deviceIcon */ null);
}
break;
diff --git a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
index 0c54720..77b1780 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
@@ -17,10 +17,12 @@
package com.android.server.companion.association;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeByteArrayAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
@@ -36,6 +38,7 @@
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.companion.AssociationInfo;
+import android.graphics.drawable.Icon;
import android.net.MacAddress;
import android.os.Environment;
import android.util.AtomicFile;
@@ -51,6 +54,7 @@
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -172,6 +176,7 @@
private static final String XML_ATTR_TIME_APPROVED = "time_approved";
private static final String XML_ATTR_LAST_TIME_CONNECTED = "last_time_connected";
private static final String XML_ATTR_SYSTEM_DATA_SYNC_FLAGS = "system_data_sync_flags";
+ private static final String XML_ATTR_DEVICE_ICON = "device_icon";
private static final String LEGACY_XML_ATTR_DEVICE = "device";
@@ -393,7 +398,7 @@
return new AssociationInfo(associationId, userId, appPackage, tag,
MacAddress.fromString(deviceAddress), null, profile, null,
/* managedByCompanionApp */ false, notify, /* revoked */ false, /* pending */ false,
- timeApproved, Long.MAX_VALUE, /* systemDataSyncFlags */ 0);
+ timeApproved, Long.MAX_VALUE, /* systemDataSyncFlags */ 0, null);
}
private static Associations readAssociationsV1(@NonNull TypedXmlPullParser parser,
@@ -444,10 +449,12 @@
parser, XML_ATTR_LAST_TIME_CONNECTED, Long.MAX_VALUE);
final int systemDataSyncFlags = readIntAttribute(parser,
XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, 0);
+ final Icon deviceIcon = byteArrayToIcon(
+ readByteArrayAttribute(parser, XML_ATTR_DEVICE_ICON));
return new AssociationInfo(associationId, userId, appPackage, tag, macAddress, displayName,
profile, null, selfManaged, notify, revoked, pending, timeApproved,
- lastTimeConnected, systemDataSyncFlags);
+ lastTimeConnected, systemDataSyncFlags, deviceIcon);
}
private static void writeAssociations(@NonNull XmlSerializer parent,
@@ -480,6 +487,8 @@
writeLongAttribute(
serializer, XML_ATTR_LAST_TIME_CONNECTED, a.getLastTimeConnectedMs());
writeIntAttribute(serializer, XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, a.getSystemDataSyncFlags());
+ writeByteArrayAttribute(
+ serializer, XML_ATTR_DEVICE_ICON, iconToByteArray(a.getDeviceIcon()));
serializer.endTag(null, XML_TAG_ASSOCIATION);
}
@@ -494,4 +503,24 @@
private static @Nullable MacAddress stringToMacAddress(@Nullable String address) {
return address != null ? MacAddress.fromString(address) : null;
}
+
+ private static byte[] iconToByteArray(Icon deviceIcon)
+ throws IOException {
+ if (deviceIcon == null) {
+ return null;
+ }
+
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ deviceIcon.writeToStream(byteStream);
+ return byteStream.toByteArray();
+ }
+
+ private static Icon byteArrayToIcon(byte[] bytes) throws IOException {
+ if (bytes == null) {
+ return null;
+ }
+
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
+ return Icon.createFromStream(byteStream);
+ }
}
diff --git a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
index d56f17b..aebd11a 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
@@ -48,6 +48,7 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManagerInternal;
+import android.graphics.drawable.Icon;
import android.net.MacAddress;
import android.os.Binder;
import android.os.Bundle;
@@ -281,7 +282,7 @@
createAssociation(userId, packageName, macAddress, request.getDisplayName(),
request.getDeviceProfile(), request.getAssociatedDevice(),
request.isSelfManaged(),
- callback, resultReceiver);
+ callback, resultReceiver, request.getDeviceIcon());
});
}
@@ -292,15 +293,15 @@
@Nullable MacAddress macAddress, @Nullable CharSequence displayName,
@Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice,
boolean selfManaged, @Nullable IAssociationRequestCallback callback,
- @Nullable ResultReceiver resultReceiver) {
+ @Nullable ResultReceiver resultReceiver, @Nullable Icon deviceIcon) {
final int id = mAssociationStore.getNextId();
final long timestamp = System.currentTimeMillis();
final AssociationInfo association = new AssociationInfo(id, userId, packageName,
/* tag */ null, macAddress, displayName, deviceProfile, associatedDevice,
selfManaged, /* notifyOnDeviceNearby */ false, /* revoked */ false,
- /* pending */ false, timestamp, Long.MAX_VALUE, /* systemDataSyncFlags */ 0);
-
+ /* pending */ false, timestamp, Long.MAX_VALUE, /* systemDataSyncFlags */ 0,
+ deviceIcon);
// Add role holder for association (if specified) and add new association to store.
maybeGrantRoleAndStoreAssociation(association, callback, resultReceiver);
}
diff --git a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index c927cd0..f37e0c9 100644
--- a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
@@ -86,7 +86,7 @@
@NonNull AssociationRequest request, int packageUid) {
enforcePermissionForRequestingProfile(context, request.getDeviceProfile(), packageUid);
- if (request.isSelfManaged()) {
+ if (request.isSelfManaged() || request.getDeviceIcon() != null) {
enforcePermissionForRequestingSelfManaged(context, packageUid);
}
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index d80e40c..504137a 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -727,10 +727,8 @@
return;
}
// Read configuration of features, libs and priv-app permissions from apex module.
- int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
- if (android.permission.flags.Flags.apexSignaturePermissionAllowlistEnabled()) {
- apexPermissionFlag |= ALLOW_SIGNATURE_PERMISSIONS;
- }
+ int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
+ | ALLOW_SIGNATURE_PERMISSIONS;
// TODO: Use a solid way to filter apex module folders?
for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
if (f.isFile() || f.getPath().contains("@")) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3666524..3bfbc55 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1189,8 +1189,8 @@
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
final boolean wasStartRequested = r.startRequested;
- r.lastActivity = SystemClock.uptimeMillis();
- r.startRequested = true;
+ mAm.mProcessStateController.setServiceLastActivityTime(r, SystemClock.uptimeMillis());
+ mAm.mProcessStateController.setStartRequested(r, true);
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
@@ -1623,7 +1623,7 @@
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
- service.startRequested = false;
+ mAm.mProcessStateController.setStartRequested(service, false);
if (service.tracker != null) {
synchronized (mAm.mProcessStats.mLock) {
service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -1812,7 +1812,7 @@
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
- r.startRequested = false;
+ mAm.mProcessStateController.setStartRequested(r, false);
if (r.tracker != null) {
synchronized (mAm.mProcessStats.mLock) {
r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2618,7 +2618,7 @@
}
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
r.foregroundNoti = notification;
- r.foregroundServiceType = foregroundServiceType;
+ mAm.mProcessStateController.setForegroundServiceType(r, foregroundServiceType);
if (!r.isForeground) {
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
@@ -2643,7 +2643,7 @@
}
active.mNumActive++;
}
- r.isForeground = true;
+ mAm.mProcessStateController.setIsForegroundService(r, true);
// The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could
// be deferred, make a copy of mAllowStartForeground and
@@ -2772,7 +2772,7 @@
}
}
- r.isForeground = false;
+ mAm.mProcessStateController.setIsForegroundService(r, false);
r.mFgsExitTime = SystemClock.uptimeMillis();
synchronized (mAm.mProcessStats.mLock) {
final ServiceState stracker = r.getTracker();
@@ -3565,7 +3565,7 @@
private void maybeUpdateShortFgsTrackingLocked(ServiceRecord sr,
boolean extendTimeout) {
if (!sr.isShortFgs()) {
- sr.clearShortFgsInfo(); // Just in case we have it.
+ mAm.mProcessStateController.clearShortFgsInfo(sr); // Just in case we have it.
unscheduleShortFgsTimeoutLocked(sr);
return;
}
@@ -3581,7 +3581,7 @@
}
}
traceInstant("short FGS start/extend: ", sr);
- sr.setShortFgsInfo(SystemClock.uptimeMillis());
+ mAm.mProcessStateController.setShortFgsInfo(sr, SystemClock.uptimeMillis());
// We'll restart the timeout.
unscheduleShortFgsTimeoutLocked(sr);
@@ -3605,7 +3605,7 @@
* Stop the timeout for a ServiceRecord, if it's of a short-FGS.
*/
private void maybeStopShortFgsTimeoutLocked(ServiceRecord sr) {
- sr.clearShortFgsInfo(); // Always clear, just in case.
+ mAm.mProcessStateController.clearShortFgsInfo(sr); // Always clear, just in case.
if (!sr.isShortFgs()) {
return;
}
@@ -3993,7 +3993,7 @@
private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) {
maybeStopShortFgsTimeoutLocked(service);
final ProcessServiceRecord psr = service.app.mServices;
- psr.stopService(service);
+ mAm.mProcessStateController.stopService(psr, service);
psr.updateBoundClientUids();
if (service.allowlistManager) {
updateAllowlistManagerLocked(psr);
@@ -4047,7 +4047,7 @@
}
}
if (anyClientActivities != psr.hasClientActivities()) {
- psr.setHasClientActivities(anyClientActivities);
+ mAm.mProcessStateController.setHasClientActivities(psr, anyClientActivities);
if (updateLru) {
mAm.updateLruProcessLocked(psr.mApp, anyClientActivities, null);
}
@@ -4216,7 +4216,8 @@
}
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
- s.lastActivity = SystemClock.uptimeMillis();
+ mAm.mProcessStateController.setServiceLastActivityTime(s,
+ SystemClock.uptimeMillis());
if (!s.hasAutoCreateConnections()) {
// This is the first binding, let the tracker know.
synchronized (mAm.mProcessStats.mLock) {
@@ -4253,12 +4254,12 @@
if (activity != null) {
activity.addConnection(c);
}
- clientPsr.addConnection(c);
+ mAm.mProcessStateController.addConnection(clientPsr, c);
c.startAssociationIfNeeded();
// Don't set hasAboveClient if binding to self to prevent modifyRawOomAdj() from
// dropping the process' adjustment level.
if (b.client != s.app && c.hasFlag(Context.BIND_ABOVE_CLIENT)) {
- clientPsr.setHasAboveClient(true);
+ mAm.mProcessStateController.setHasAboveClient(clientPsr, true);
}
if (c.hasFlag(BIND_ALLOW_WHITELIST_MANAGEMENT)) {
s.allowlistManager = true;
@@ -4274,7 +4275,8 @@
if (s.app != null && s.app.mState != null
&& s.app.mState.getCurProcState() <= PROCESS_STATE_TOP
&& c.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)) {
- s.lastTopAlmostPerceptibleBindRequestUptimeMs = SystemClock.uptimeMillis();
+ mAm.mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s,
+ SystemClock.uptimeMillis());
}
if (s.app != null) {
@@ -4312,7 +4314,8 @@
boolean needOomAdj = false;
if (c.hasFlag(Context.BIND_AUTO_CREATE)) {
- s.lastActivity = SystemClock.uptimeMillis();
+ mAm.mProcessStateController.setServiceLastActivityTime(s,
+ SystemClock.uptimeMillis());
needOomAdj = (serviceBindingOomAdjPolicy
& SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) == 0;
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
@@ -4328,7 +4331,7 @@
if (s.app != null) {
ProcessServiceRecord servicePsr = s.app.mServices;
if (c.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
- servicePsr.setTreatLikeActivity(true);
+ mAm.mProcessStateController.setTreatLikeActivity(servicePsr, true);
}
if (s.allowlistManager) {
servicePsr.mAllowlistManager = true;
@@ -4575,7 +4578,9 @@
}
// This could have made the service less important.
if (r.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
- psr.setTreatLikeActivity(true);
+ // TODO(b/367545398): the following line is a bug. A service unbind
+ // should potentially lower a process's importance, not elevate it.
+ mAm.mProcessStateController.setTreatLikeActivity(psr, true);
mAm.updateLruProcessLocked(app, true, null);
}
// If the bindee is more important than the binder, we may skip the OomAdjuster.
@@ -5077,7 +5082,10 @@
+ " requires " + r.permission);
return new ServiceLookupResult(r.permission);
} else if ((Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
- || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission))
+ || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission)
+ || Manifest.permission.BIND_WEARABLE_SENSING_SERVICE.equals(r.permission)
+ || Manifest.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE.equals(
+ r.permission))
&& callingUid != Process.SYSTEM_UID) {
// Hotword detection and visual query detection must run in its own sandbox, and we
// don't even trust its enclosing application to bind to it - only the system.
@@ -5162,8 +5170,9 @@
}
if (r.app != null) {
psr = r.app.mServices;
- psr.startExecutingService(r);
- psr.setExecServicesFg(psr.shouldExecServicesFg() || fg);
+ mAm.mProcessStateController.startExecutingService(psr, r);
+ mAm.mProcessStateController.setExecServicesFg(psr,
+ psr.shouldExecServicesFg() || fg);
if (timeoutNeeded && psr.numberOfExecutingServices() == 1) {
if (!shouldSkipTimeout) {
scheduleServiceTimeoutLocked(r.app);
@@ -5175,7 +5184,7 @@
} else if (r.app != null && fg) {
psr = r.app.mServices;
if (!psr.shouldExecServicesFg()) {
- psr.setExecServicesFg(true);
+ mAm.mProcessStateController.setExecServicesFg(psr, true);
if (timeoutNeeded) {
if (!shouldSkipTimeout) {
scheduleServiceTimeoutLocked(r.app);
@@ -6020,11 +6029,13 @@
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
r.setProcess(app, thread, pid, uidRecord);
- r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
+ final long now = SystemClock.uptimeMillis();
+ r.restartTime = now;
+ mAm.mProcessStateController.setServiceLastActivityTime(r, now);
final boolean skipOomAdj = (serviceBindingOomAdjPolicy
& SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) != 0;
final ProcessServiceRecord psr = app.mServices;
- final boolean newService = psr.startService(r);
+ final boolean newService = mAm.mProcessStateController.startService(psr, r);
bumpServiceExecutingLocked(r, execInFg, "create",
OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */,
skipOomAdj /* skipTimeoutIfPossible */);
@@ -6083,7 +6094,7 @@
// Cleanup.
if (newService) {
- psr.stopService(r);
+ mAm.mProcessStateController.stopService(psr, r);
r.setProcess(null, null, 0, null);
}
@@ -6428,7 +6439,7 @@
mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
}
- r.isForeground = false;
+ mAm.mProcessStateController.setIsForegroundService(r, false);
r.mFgsNotificationWasDeferred = false;
dropFgsNotificationStateLocked(r);
r.foregroundId = 0;
@@ -6579,9 +6590,9 @@
}
if (b.client != skipApp) {
final ProcessServiceRecord psr = b.client.mServices;
- psr.removeConnection(c);
+ mAm.mProcessStateController.removeConnection(psr, c);
if (c.hasFlag(Context.BIND_ABOVE_CLIENT)) {
- psr.updateHasAboveClientLocked();
+ mAm.mProcessStateController.updateHasAboveClientLocked(psr);
}
// If this connection requested allowlist management, see if we should
// now clear that state.
@@ -6597,7 +6608,7 @@
}
// And for almost perceptible exceptions.
if (c.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)) {
- psr.updateHasTopStartedAlmostPerceptibleServices();
+ mAm.mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(psr);
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
@@ -6796,8 +6807,8 @@
final ProcessServiceRecord psr = r.app.mServices;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortInstanceName);
- psr.setExecServicesFg(false);
- psr.stopExecutingService(r);
+ mAm.mProcessStateController.setExecServicesFg(psr, false);
+ mAm.mProcessStateController.stopExecutingService(psr, r);
if (psr.numberOfExecutingServices() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortInstanceName);
@@ -6806,7 +6817,7 @@
// Need to re-evaluate whether the app still needs to be in the foreground.
for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
if (psr.getExecutingServiceAt(i).executeFg) {
- psr.setExecServicesFg(true);
+ mAm.mProcessStateController.setExecServicesFg(psr, true);
break;
}
}
@@ -6819,9 +6830,9 @@
}
if (oomAdjReason != OOM_ADJ_REASON_NONE) {
if (enqueueOomAdj) {
- mAm.enqueueOomAdjTargetLocked(r.app);
+ mAm.mProcessStateController.enqueueUpdateTarget(r.app);
} else {
- mAm.updateOomAdjLocked(r.app, oomAdjReason);
+ mAm.mProcessStateController.runUpdate(r.app, oomAdjReason);
}
} else {
// Skip oom adj if it wasn't bumped during the bumpServiceExecutingLocked()
@@ -7206,8 +7217,7 @@
removeConnectionLocked(r, app, null, true);
}
updateServiceConnectionActivitiesLocked(psr);
- psr.removeAllConnections();
- psr.removeAllSdkSandboxConnections();
+ mAm.mProcessStateController.removeAllConnections(psr);
psr.mAllowlistManager = false;
@@ -7217,7 +7227,7 @@
mAm.mBatteryStatsService.noteServiceStopLaunch(sr.appInfo.uid, sr.name.getPackageName(),
sr.name.getClassName());
if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
- sr.app.mServices.stopService(sr);
+ mAm.mProcessStateController.stopService(psr, sr);
sr.app.mServices.updateBoundClientUids();
}
sr.setProcess(null, null, 0, null);
@@ -7287,7 +7297,7 @@
// Unless the process is persistent, this process record is going away,
// so make sure the service is cleaned out of it.
if (!app.isPersistent()) {
- psr.stopService(sr);
+ mAm.mProcessStateController.stopService(psr, sr);
psr.updateBoundClientUids();
}
@@ -7328,7 +7338,7 @@
// Update to stopped state because the explicit start is gone. The service is
// scheduled to restart for other reason (e.g. connections) so we don't bring
// down it.
- sr.startRequested = false;
+ mAm.mProcessStateController.setStartRequested(sr, false);
if (sr.tracker != null) {
synchronized (mAm.mProcessStats.mLock) {
sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -7342,7 +7352,7 @@
mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_STOP_SERVICE);
if (!allowRestart) {
- psr.stopAllServices();
+ mAm.mProcessStateController.stopAllServices(psr);
psr.clearBoundClientUids();
// Make sure there are no more restarting services for this process.
@@ -7384,7 +7394,7 @@
}
}
- psr.stopAllExecutingServices();
+ mAm.mProcessStateController.stopAllExecutingServices(psr);
psr.noteScheduleServiceTimeoutPending(false);
}
@@ -9210,14 +9220,14 @@
new ForegroundServiceDelegation(options, connection);
r.mFgsDelegation = delegation;
mFgsDelegations.put(delegation, r);
- r.isForeground = true;
+ mAm.mProcessStateController.setIsForegroundService(r, true);
r.mFgsEnterTime = SystemClock.uptimeMillis();
- r.foregroundServiceType = options.mForegroundServiceTypes;
+ mAm.mProcessStateController.setForegroundServiceType(r, options.mForegroundServiceTypes);
r.updateOomAdjSeq();
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId,
BackgroundStartPrivileges.NONE, false /* isBindService */);
final ProcessServiceRecord psr = callerApp.mServices;
- final boolean newService = psr.startService(r);
+ final boolean newService = mAm.mProcessStateController.startService(psr, r);
// updateOomAdj.
updateServiceForegroundLocked(psr, /* oomAdj= */ true);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 74437cd..bcca20b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -626,6 +626,8 @@
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ");
OomAdjuster mOomAdjuster;
+ @GuardedBy("this")
+ ProcessStateController mProcessStateController;
static final String EXTRA_TITLE = "android.intent.extra.TITLE";
static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
@@ -1958,7 +1960,7 @@
new HostingRecord(HostingRecord.HOSTING_TYPE_SYSTEM));
app.setPersistent(true);
app.setPid(MY_PID);
- app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ);
+ mProcessStateController.setMaxAdj(app, ProcessList.SYSTEM_ADJ);
app.makeActive(new ApplicationThreadDeferred(mSystemThread.getApplicationThread()),
mProcessStats);
app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
@@ -2394,9 +2396,11 @@
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
- ? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread)
- : new OomAdjuster(this, mProcessList, activeUids, handlerThread);
+ mProcessStateController = new ProcessStateController.Builder(this, mProcessList, activeUids)
+ .setHandlerThread(handlerThread)
+ .useModernOomAdjuster(mConstants.ENABLE_NEW_OOMADJ)
+ .build();
+ mOomAdjuster = mProcessStateController.getOomAdjuster();
mIntentFirewall = injector.getIntentFirewall();
mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
@@ -2459,9 +2463,10 @@
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(),
new LowMemDetector(this));
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
- ? new OomAdjusterModernImpl(this, mProcessList, activeUids)
- : new OomAdjuster(this, mProcessList, activeUids);
+ mProcessStateController = new ProcessStateController.Builder(this, mProcessList, activeUids)
+ .useModernOomAdjuster(mConstants.ENABLE_NEW_OOMADJ)
+ .build();
+ mOomAdjuster = mProcessStateController.getOomAdjuster();
mBroadcastQueue = mInjector.getBroadcastQueue(this);
mBroadcastController = new BroadcastController(mContext, this, mBroadcastQueue);
@@ -4574,7 +4579,7 @@
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
synchronized (mProcLock) {
- mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mProcessStateController.setAttachingProcessStatesLSP(app);
clearProcessForegroundLocked(app);
app.setDebugging(false);
app.setKilledByAm(false);
@@ -4770,7 +4775,7 @@
app.makeActive(new ApplicationThreadDeferred(thread), mProcessStats);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
}
- app.setPendingFinishAttach(true);
+ mProcessStateController.setPendingFinishAttach(app, true);
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
@@ -4854,7 +4859,7 @@
synchronized (this) {
// Mark the finish attach application phase as completed
- app.setPendingFinishAttach(false);
+ mProcessStateController.setPendingFinishAttach(app, false);
final boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
final String processName = app.processName;
@@ -5009,7 +5014,7 @@
// If another follow up update is needed, it will be scheduled by OomAdjuster.
mHandler.removeMessages(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG);
synchronized (this) {
- mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
}
}
@@ -5804,10 +5809,10 @@
if (pr == null) {
return;
}
- pr.mState.setForcingToImportant(null);
+ mProcessStateController.setForcingToImportant(pr, null);
clearProcessForegroundLocked(pr);
}
- updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
+ mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
}
}
@@ -5830,7 +5835,7 @@
oldToken.token.unlinkToDeath(oldToken, 0);
mImportantProcesses.remove(pid);
if (pr != null) {
- pr.mState.setForcingToImportant(null);
+ mProcessStateController.setForcingToImportant(pr, null);
}
changed = true;
}
@@ -5844,7 +5849,7 @@
try {
token.linkToDeath(newToken, 0);
mImportantProcesses.put(pid, newToken);
- pr.mState.setForcingToImportant(newToken);
+ mProcessStateController.setForcingToImportant(pr, newToken);
changed = true;
} catch (RemoteException e) {
// If the process died while doing this, we will later
@@ -5854,7 +5859,7 @@
}
if (changed) {
- updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
+ mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
}
}
}
@@ -7274,7 +7279,7 @@
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
app.setPersistent(true);
- app.mState.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(app, ProcessList.PERSISTENT_PROC_ADJ);
}
if (app.getThread() == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
@@ -7377,7 +7382,7 @@
mServices.updateScreenStateLocked(isAwake);
reportCurWakefulnessUsageEvent();
mActivityTaskManager.onScreenAwakeChanged(isAwake);
- mOomAdjuster.onWakefulnessChanged(wakefulness);
+ mProcessStateController.setWakefulness(wakefulness);
updateOomAdjLocked(OOM_ADJ_REASON_UI_VISIBILITY);
}
@@ -8346,16 +8351,10 @@
Slog.w(TAG, "setHasTopUi called on unknown pid: " + pid);
return;
}
- if (pr.mState.hasTopUi() != hasTopUi) {
- if (DEBUG_OOM_ADJ) {
- Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + pid);
- }
- pr.mState.setHasTopUi(hasTopUi);
- changed = true;
- }
+ changed = mProcessStateController.setHasTopUi(pr, hasTopUi);
}
if (changed) {
- updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
+ mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
}
}
} finally {
@@ -14084,10 +14083,14 @@
proc.setInFullBackup(true);
}
r.app = proc;
+ // TODO(b/369300367): This code suggests there could be a previous backup being
+ // replaced here, but an OomAdjsuter update is not triggered on the previous app
+ // (whose state will change from being removed from mBackupTargets).
final BackupRecord backupTarget = mBackupTargets.get(targetUserId);
oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
newBackupUid = proc.isInFullBackup() ? r.appInfo.uid : -1;
mBackupTargets.put(targetUserId, r);
+ mProcessStateController.setBackupTarget(proc, targetUserId);
proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP);
@@ -14141,6 +14144,7 @@
}
mBackupTargets.removeAt(indexOfKey);
}
+ mProcessStateController.stopBackupTarget(userId);
}
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
@@ -14219,6 +14223,8 @@
// Not backing this app up any more; reset its OOM adjustment
final ProcessRecord proc = backupTarget.app;
+ // TODO(b/369300367): Triggering the update before the state is actually set
+ // seems wrong.
updateOomAdjLocked(proc, OOM_ADJ_REASON_BACKUP);
proc.setInFullBackup(false);
proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BACKUP);
@@ -14237,6 +14243,7 @@
}
} finally {
mBackupTargets.delete(userId);
+ mProcessStateController.stopBackupTarget(userId);
}
}
@@ -15309,7 +15316,8 @@
proc.info.packageName, proc.info.uid, proc.getPid(), isForeground);
}
}
- psr.setHasForegroundServices(isForeground, fgServiceTypes, hasTypeNoneFgs);
+ mProcessStateController.setHasForegroundServices(psr, isForeground, fgServiceTypes,
+ hasTypeNoneFgs);
ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
proc.info.uid);
if (isForeground) {
@@ -15340,7 +15348,7 @@
ProcessChangeItem.CHANGE_FOREGROUND_SERVICES, fgServiceTypes);
}
if (oomAdj) {
- updateOomAdjLocked(proc, OOM_ADJ_REASON_UI_VISIBILITY);
+ mProcessStateController.runUpdate(proc, OOM_ADJ_REASON_UI_VISIBILITY);
}
}
@@ -15390,7 +15398,7 @@
*/
@GuardedBy("this")
void enqueueOomAdjTargetLocked(ProcessRecord app) {
- mOomAdjuster.enqueueOomAdjTargetLocked(app);
+ mProcessStateController.enqueueUpdateTarget(app);
}
/**
@@ -15398,7 +15406,7 @@
*/
@GuardedBy("this")
void removeOomAdjTargetLocked(ProcessRecord app, boolean procDied) {
- mOomAdjuster.removeOomAdjTargetLocked(app, procDied);
+ mProcessStateController.removeUpdateTarget(app, procDied);
}
/**
@@ -15407,7 +15415,7 @@
*/
@GuardedBy("this")
void updateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) {
- mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason);
+ mProcessStateController.runPendingUpdate(oomAdjReason);
}
static final class ProcStatsRunnable implements Runnable {
@@ -15426,7 +15434,7 @@
@GuardedBy("this")
final void updateOomAdjLocked(@OomAdjReason int oomAdjReason) {
- mOomAdjuster.updateOomAdjLocked(oomAdjReason);
+ mProcessStateController.runFullUpdate(oomAdjReason);
}
/**
@@ -15438,7 +15446,7 @@
*/
@GuardedBy("this")
final boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) {
- return mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
+ return mProcessStateController.runUpdate(app, oomAdjReason);
}
@Override
@@ -15703,7 +15711,7 @@
@GuardedBy({"this", "mProcLock"})
final void setUidTempAllowlistStateLSP(int uid, boolean onAllowlist) {
- mOomAdjuster.setUidTempAllowlistStateLSP(uid, onAllowlist);
+ mProcessStateController.setUidTempAllowlistStateLSP(uid, onAllowlist);
}
private void trimApplications(boolean forceFullOomAdj, @OomAdjReason int oomAdjReason) {
@@ -16753,12 +16761,9 @@
return;
}
}
- if (pr.mState.hasOverlayUi() == hasOverlayUi) {
- return;
+ if (mProcessStateController.setHasOverlayUi(pr, hasOverlayUi)) {
+ mProcessStateController.runUpdate(pr, OOM_ADJ_REASON_UI_VISIBILITY);
}
- pr.mState.setHasOverlayUi(hasOverlayUi);
- //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
- updateOomAdjLocked(pr, OOM_ADJ_REASON_UI_VISIBILITY);
}
}
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index dda48ad..4f2d69e 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1356,6 +1356,7 @@
@GuardedBy("mService")
void setMemFactorOverrideLocked(@MemFactor int factor) {
mMemFactorOverride = factor;
+ mService.mProcessStateController.setIsLastMemoryLevelNormal(isLastMemoryLevelNormal());
}
@GuardedBy({"mService", "mProcLock"})
@@ -1423,6 +1424,7 @@
}
mLastMemoryLevel = memFactor;
+ mService.mProcessStateController.setIsLastMemoryLevelNormal(isLastMemoryLevelNormal());
mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
// Dispatch UI_HIDDEN to processes that need it
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index da40826..221938a 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -325,7 +325,8 @@
final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
boolean success = !serviceBindingOomAdjPolicy()
|| mService.mOomAdjuster.evaluateProviderConnectionAdd(r, cpr.proc)
- ? mService.updateOomAdjLocked(cpr.proc, OOM_ADJ_REASON_GET_PROVIDER)
+ ? mService.mProcessStateController.runUpdate(cpr.proc,
+ OOM_ADJ_REASON_GET_PROVIDER)
: true;
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
@@ -534,10 +535,9 @@
if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
Slog.d(TAG, "Installing in existing process " + proc);
}
- final ProcessProviderRecord pr = proc.mProviders;
- if (!pr.hasProvider(cpi.name)) {
+ if (mService.mProcessStateController.addPublishedProvider(proc,
+ cpi.name, cpr)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
- pr.installProvider(cpi.name, cpr);
mService.mOomAdjuster.unfreezeTemporarily(proc,
CachedAppOptimizer.UNFREEZE_REASON_GET_PROVIDER);
try {
@@ -881,7 +881,8 @@
ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
if (localCpr.hasExternalProcessHandles()) {
- if (localCpr.removeExternalProcessHandleLocked(token)) {
+ if (mService.mProcessStateController.removeExternalProviderClient(localCpr,
+ token)) {
mService.updateOomAdjLocked(localCpr.proc, OOM_ADJ_REASON_REMOVE_PROVIDER);
} else {
Slog.e(TAG, "Attempt to remove content provider " + localCpr
@@ -1447,7 +1448,8 @@
String callingPackage, String callingTag, boolean stable, boolean updateLru,
long startTime, ProcessList processList, @UserIdInt int expectedUserId) {
if (r == null) {
- cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+ mService.mProcessStateController.addExternalProviderClient(cpr, externalProcessToken,
+ callingUid, callingTag);
return null;
}
@@ -1470,7 +1472,7 @@
if (cpr.proc != null) {
cpr.proc.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
}
- pr.addProviderConnection(conn);
+ mService.mProcessStateController.addProviderConnection(r, conn);
mService.startAssociationLocked(r.uid, r.processName, r.mState.getCurProcState(),
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
if (updateLru && cpr.proc != null
@@ -1493,7 +1495,8 @@
ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable,
boolean enforceDelay, boolean updateOomAdj) {
if (conn == null) {
- cpr.removeExternalProcessHandleLocked(externalProcessToken);
+ mService.mProcessStateController.removeExternalProviderClient(cpr,
+ externalProcessToken);
return false;
}
@@ -1537,14 +1540,15 @@
if (cpr.proc != null && !hasProviderConnectionLocked(cpr.proc)) {
cpr.proc.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
}
- conn.client.mProviders.removeProviderConnection(conn);
+ mService.mProcessStateController.removeProviderConnection(conn.client, conn);
if (conn.client.mState.getSetProcState()
< ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
// The client is more important than last activity -- note the time this
// is happening, so we keep the old provider process around a bit as last
// activity to avoid thrashing it.
if (cpr.proc != null) {
- cpr.proc.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
+ mService.mProcessStateController.setLastProviderTime(cpr.proc,
+ SystemClock.uptimeMillis());
}
}
mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
@@ -1821,7 +1825,7 @@
}
}
if (removed && cpr.proc != null) {
- cpr.proc.mProviders.removeProvider(cpr.info.name);
+ mService.mProcessStateController.removePublishedProvider(cpr.proc, cpr.info.name);
}
}
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 2a30ad0..61079fc 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -54,8 +54,9 @@
per-file *Permission* = patb@google.com
per-file *Package* = patb@google.com
-# OOM Adjuster
+# OOM Adjuster & ProcessStateController
per-file *Oom* = file:/OOM_ADJUSTER_OWNERS
+per-file ProcessStateController.java = file:/OOM_ADJUSTER_OWNERS
# Miscellaneous
per-file SettingsToPropertiesMapper.java = omakoto@google.com, yamasani@google.com, dzshen@google.com, zhidou@google.com, tedbauer@google.com
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 4073ab8..e8f7b5f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -130,6 +130,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal.OomAdjReason;
import android.app.ActivityThread;
@@ -376,6 +377,7 @@
final ActivityManagerService mService;
final Injector mInjector;
+ final GlobalState mGlobalState;
final ProcessList mProcessList;
final ActivityManagerGlobalLock mProcLock;
@@ -470,15 +472,23 @@
}
+ // TODO(b/346822474): hook up global state usage.
+ interface GlobalState {
+ /** Is device's screen on. */
+ boolean isAwake();
+
+ /** What process is running a backup for a given userId. */
+ ProcessRecord getBackupTarget(@UserIdInt int userId);
+
+ /** Is memory level normal since last evaluation. */
+ boolean isLastMemoryLevelNormal();
+ }
+
boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
ApplicationInfo app, boolean defaultValue) {
return mInjector.isChangeEnabled(cachedCompatChangeId, app, defaultValue);
}
- OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
- this(service, processList, activeUids, createAdjusterThread());
- }
-
static ServiceThread createAdjusterThread() {
// The process group is usually critical to the response time of foreground app, so the
// setter should apply it as soon as possible.
@@ -489,18 +499,9 @@
}
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
- ServiceThread adjusterThread) {
- this(service, processList, activeUids, adjusterThread, new Injector());
- }
-
- OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
- Injector injector) {
- this(service, processList, activeUids, createAdjusterThread(), injector);
- }
-
- OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
- ServiceThread adjusterThread, Injector injector) {
+ ServiceThread adjusterThread, GlobalState globalState, Injector injector) {
mService = service;
+ mGlobalState = globalState;
mInjector = injector;
mProcessList = processList;
mProcLock = service.mProcLock;
@@ -1816,9 +1817,36 @@
}
}
+ private boolean isDeviceFullyAwake() {
+ if (Flags.pushGlobalStateToOomadjuster()) {
+ return mGlobalState.isAwake();
+ } else {
+ return mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE;
+ }
+ }
+
private boolean isScreenOnOrAnimatingLocked(ProcessStateRecord state) {
- return mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
- || state.isRunningRemoteAnimation();
+ return isDeviceFullyAwake() || state.isRunningRemoteAnimation();
+ }
+
+ private boolean isBackupProcess(ProcessRecord app) {
+ if (Flags.pushGlobalStateToOomadjuster()) {
+ return app == mGlobalState.getBackupTarget(app.userId);
+ } else {
+ final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
+ if (backupTarget == null) {
+ return false;
+ }
+ return app == backupTarget.app;
+ }
+ }
+
+ private boolean isLastMemoryLevelNormal() {
+ if (Flags.pushGlobalStateToOomadjuster()) {
+ return mGlobalState.isLastMemoryLevelNormal();
+ } else {
+ return mService.mAppProfiler.isLastMemoryLevelNormal();
+ }
}
@GuardedBy({"mService", "mProcLock"})
@@ -2259,8 +2287,7 @@
state.setHasStartedServices(false);
state.setAdjSeq(mAdjSeq);
- final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
- if (backupTarget != null && app == backupTarget.app) {
+ if (isBackupProcess(app)) {
// If possible we want to avoid killing apps while they're being backed up
if (adj > BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
@@ -2526,8 +2553,7 @@
double cachedRestoreThreshold =
mProcessList.getCachedRestoreThresholdKb() * thresholdModifier;
- if (!mService.mAppProfiler.isLastMemoryLevelNormal()
- && lastPssOrRss >= cachedRestoreThreshold) {
+ if (isLastMemoryLevelNormal() && lastPssOrRss >= cachedRestoreThreshold) {
state.setServiceHighRam(true);
state.setServiceB(true);
//Slog.i(TAG, "ADJ " + app + " high ram!");
@@ -2621,7 +2647,7 @@
// Put bound foreground services in a special sched group for additional
// restrictions on screen off
if (state.getCurProcState() >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
- && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
+ && !isDeviceFullyAwake()
&& !state.shouldScheduleLikeTopApp()) {
if (schedGroup > SCHED_GROUP_RESTRICTED) {
schedGroup = SCHED_GROUP_RESTRICTED;
@@ -2910,8 +2936,7 @@
clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
} else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- } else if (mService.mWakefulness.get()
- == PowerManagerInternal.WAKEFULNESS_AWAKE
+ } else if (isDeviceFullyAwake()
&& cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
} else {
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index fb1c2e9..e452c45 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -756,18 +756,9 @@
new ComputeConnectionsConsumer();
OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
- ActiveUids activeUids) {
- this(service, processList, activeUids, createAdjusterThread());
- }
-
- OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
- ActiveUids activeUids, ServiceThread adjusterThread) {
- super(service, processList, activeUids, adjusterThread);
- }
-
- OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
- ActiveUids activeUids, Injector injector) {
- super(service, processList, activeUids, injector);
+ ActiveUids activeUids, ServiceThread adjusterThread, GlobalState globalState,
+ Injector injector) {
+ super(service, processList, activeUids, adjusterThread, globalState, injector);
}
private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 57922d5..2485626 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3439,12 +3439,12 @@
state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT);
r.setPersistent(true);
- state.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ);
+ mService.mProcessStateController.setMaxAdj(r, ProcessList.PERSISTENT_PROC_ADJ);
}
if (isolated && isolatedUid != 0) {
// Special case for startIsolatedProcess (internal only) - assume the process
// is required by the system server to prevent it being killed.
- state.setMaxAdj(ProcessList.PERSISTENT_SERVICE_ADJ);
+ mService.mProcessStateController.setMaxAdj(r, ProcessList.PERSISTENT_SERVICE_ADJ);
}
addProcessNameLocked(r);
return r;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 3e71d00..b51db13 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
+import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -1192,7 +1193,7 @@
setWaitingToKill(null);
mState.onCleanupApplicationRecordLSP();
- mServices.onCleanupApplicationRecordLocked();
+ mService.mProcessStateController.onCleanupApplicationRecord(mServices);
mReceivers.onCleanupApplicationRecordLocked();
mService.mOomAdjuster.onProcessEndLocked(this);
@@ -1638,7 +1639,7 @@
updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, true /* updateOomAdj */);
setPendingUiClean(true);
- mState.setHasShownUi(true);
+ mService.mProcessStateController.setHasShownUi(this, true);
mState.forceProcessStateUpTo(topProcessState);
}
}
@@ -1657,7 +1658,10 @@
return;
}
synchronized (mService) {
- mState.setRunningRemoteAnimation(runningRemoteAnimation);
+ if (mService.mProcessStateController.setRunningRemoteAnimation(this,
+ runningRemoteAnimation)) {
+ mService.mProcessStateController.runUpdate(this, OOM_ADJ_REASON_UI_VISIBILITY);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ProcessStateController.java b/services/core/java/com/android/server/am/ProcessStateController.java
new file mode 100644
index 0000000..428df23
--- /dev/null
+++ b/services/core/java/com/android/server/am/ProcessStateController.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2024 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.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.PowerManagerInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.ServiceThread;
+
+/**
+ * ProcessStateController is responsible for maintaining state that can affect the OomAdjuster
+ * computations of a process. Any state that can affect a process's importance must be set by
+ * only ProcessStateController.
+ */
+public class ProcessStateController {
+ public static String TAG = "ProcessStateController";
+
+ private final OomAdjuster mOomAdjuster;
+
+ private final GlobalState mGlobalState = new GlobalState();
+
+ private ProcessStateController(ActivityManagerService ams, ProcessList processList,
+ ActiveUids activeUids, ServiceThread handlerThread, OomAdjuster.Injector oomAdjInjector,
+ boolean useOomAdjusterModernImpl) {
+ mOomAdjuster = useOomAdjusterModernImpl
+ ? new OomAdjusterModernImpl(ams, processList, activeUids, handlerThread,
+ mGlobalState, oomAdjInjector)
+ : new OomAdjuster(ams, processList, activeUids, handlerThread, mGlobalState,
+ oomAdjInjector);
+ }
+
+ /**
+ * Get the instance of OomAdjuster that ProcessStateController is using.
+ * Must only be interacted with while holding the ActivityManagerService lock.
+ */
+ public OomAdjuster getOomAdjuster() {
+ return mOomAdjuster;
+ }
+
+ /**
+ * Add a process to evaluated the next time an update is run.
+ */
+ public void enqueueUpdateTarget(@NonNull ProcessRecord proc) {
+ mOomAdjuster.enqueueOomAdjTargetLocked(proc);
+ }
+
+ /**
+ * Remove a process that was added by {@link #enqueueUpdateTarget}.
+ */
+ public void removeUpdateTarget(@NonNull ProcessRecord proc, boolean procDied) {
+ mOomAdjuster.removeOomAdjTargetLocked(proc, procDied);
+ }
+
+ /**
+ * Trigger an update on a single process (and any processes that have been enqueued with
+ * {@link #enqueueUpdateTarget}).
+ */
+ public boolean runUpdate(@NonNull ProcessRecord proc,
+ @ActivityManagerInternal.OomAdjReason int oomAdjReason) {
+ return mOomAdjuster.updateOomAdjLocked(proc, oomAdjReason);
+ }
+
+ /**
+ * Trigger an update on all processes that have been enqueued with {@link #enqueueUpdateTarget}.
+ */
+ public void runPendingUpdate(@ActivityManagerInternal.OomAdjReason int oomAdjReason) {
+ mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason);
+ }
+
+ /**
+ * Trigger an update on all processes.
+ */
+ public void runFullUpdate(@ActivityManagerInternal.OomAdjReason int oomAdjReason) {
+ mOomAdjuster.updateOomAdjLocked(oomAdjReason);
+ }
+
+ /**
+ * Trigger an update on any processes that have been marked for follow up during a previous
+ * update.
+ */
+ public void runFollowUpUpdate() {
+ mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ }
+
+ private static class GlobalState implements OomAdjuster.GlobalState {
+ public boolean isAwake = true;
+ // TODO(b/369300367): Maintaining global state for backup processes is a bit convoluted.
+ // ideally the state gets migrated to ProcessStateRecord.
+ public final SparseArray<ProcessRecord> backupTargets = new SparseArray<>();
+ public boolean isLastMemoryLevelNormal = true;
+
+ public boolean isAwake() {
+ return isAwake;
+ }
+
+ public ProcessRecord getBackupTarget(@UserIdInt int userId) {
+ return backupTargets.get(userId);
+ }
+
+ public boolean isLastMemoryLevelNormal() {
+ return isLastMemoryLevelNormal;
+ }
+ }
+
+ /*************************** Global State Events ***************************/
+ /**
+ * Set which process state Top processes should get.
+ */
+ public void setTopProcessState(@ActivityManager.ProcessState int procState) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set whether to give Top processes the Top sched group.
+ */
+ public void setUseTopSchedGroupForTopProcess(boolean useTopSchedGroup) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set the Top process.
+ */
+ public void setTopApp(@Nullable ProcessRecord proc) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set which process is considered the Home process, if any.
+ */
+ public void setHomeProcess(@Nullable ProcessRecord proc) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set which process is considered the Heavy Weight process, if any.
+ */
+ public void setHeavyWeightProcess(@Nullable ProcessRecord proc) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set which process is showing UI while the screen is off, if any.
+ */
+ public void setVisibleDozeUiProcess(@Nullable ProcessRecord proc) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set which process is considered the Previous process, if any.
+ */
+ public void setPreviousProcess(@Nullable ProcessRecord proc) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set what wakefulness state the screen is in.
+ */
+ public void setWakefulness(int wakefulness) {
+ mGlobalState.isAwake = (wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mOomAdjuster.onWakefulnessChanged(wakefulness);
+ }
+
+ /**
+ * Set for a given user what process is currently running a backup, if any.
+ */
+ public void setBackupTarget(@NonNull ProcessRecord proc, @UserIdInt int userId) {
+ mGlobalState.backupTargets.put(userId, proc);
+ }
+
+ /**
+ * No longer consider any process running a backup for a given user.
+ */
+ public void stopBackupTarget(@UserIdInt int userId) {
+ mGlobalState.backupTargets.delete(userId);
+ }
+
+ /**
+ * Set whether the last known memory level is normal.
+ */
+ public void setIsLastMemoryLevelNormal(boolean isMemoryNormal) {
+ mGlobalState.isLastMemoryLevelNormal = isMemoryNormal;
+ }
+
+ /***************************** UID State Events ****************************/
+ /**
+ * Set a UID as temp allowlisted.
+ */
+ public void setUidTempAllowlistStateLSP(int uid, boolean allowList) {
+ mOomAdjuster.setUidTempAllowlistStateLSP(uid, allowList);
+ }
+
+ /*********************** Process Miscellaneous Events **********************/
+ /**
+ * Set the maximum adj score a process can be assigned.
+ */
+ public void setMaxAdj(@NonNull ProcessRecord proc, int adj) {
+ proc.mState.setMaxAdj(adj);
+ }
+
+ /**
+ * Initialize a process that is being attached.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ public void setAttachingProcessStatesLSP(@NonNull ProcessRecord proc) {
+ mOomAdjuster.setAttachingProcessStatesLSP(proc);
+ }
+
+ /**
+ * Note whether a process is pending attach or not.
+ */
+ public void setPendingFinishAttach(@NonNull ProcessRecord proc, boolean pendingFinishAttach) {
+ proc.setPendingFinishAttach(pendingFinishAttach);
+ }
+
+ /**
+ * Set what sched group to grant a process due to running a broadcast.
+ * {@link ProcessList.SCHED_GROUP_UNDEFINED} means the process is not running a broadcast.
+ */
+ public void setBroadcastSchedGroup(@NonNull ProcessRecord proc, int schedGroup) {
+ // TODO(b/302575389): Migrate state pulled from BroadcastQueue to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /********************* Process Visibility State Events *********************/
+ /**
+ * Note whether a process has Top UI or not.
+ *
+ * @return true if the state changed, otherwise returns false.
+ */
+ public boolean setHasTopUi(@NonNull ProcessRecord proc, boolean hasTopUi) {
+ if (proc.mState.hasTopUi() == hasTopUi) return false;
+ if (DEBUG_OOM_ADJ) {
+ Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + proc.getPid());
+ }
+ proc.mState.setHasTopUi(hasTopUi);
+ return true;
+ }
+
+ /**
+ * Note whether a process is displaying Overlay UI or not.
+ *
+ * @return true if the state changed, otherwise returns false.
+ */
+ public boolean setHasOverlayUi(@NonNull ProcessRecord proc, boolean hasOverlayUi) {
+ if (proc.mState.hasOverlayUi() == hasOverlayUi) return false;
+ proc.mState.setHasOverlayUi(hasOverlayUi);
+ return true;
+ }
+
+
+ /**
+ * Note whether a process is running a remote animation.
+ *
+ * @return true if the state changed, otherwise returns false.
+ */
+ public boolean setRunningRemoteAnimation(@NonNull ProcessRecord proc,
+ boolean runningRemoteAnimation) {
+ if (proc.mState.isRunningRemoteAnimation() == runningRemoteAnimation) return false;
+ if (DEBUG_OOM_ADJ) {
+ Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
+ + " for pid=" + proc.getPid());
+ }
+ proc.mState.setRunningRemoteAnimation(runningRemoteAnimation);
+ return true;
+ }
+
+ /**
+ * Note that the process is showing a toast.
+ */
+ public void setForcingToImportant(@NonNull ProcessRecord proc,
+ @Nullable Object forcingToImportant) {
+ if (proc.mState.getForcingToImportant() == forcingToImportant) return;
+ proc.mState.setForcingToImportant(forcingToImportant);
+ }
+
+ /**
+ * Note that the process has shown UI at some point in its life.
+ */
+ public void setHasShownUi(@NonNull ProcessRecord proc, boolean hasShownUi) {
+ // This arguably should be turned into an internal state of OomAdjuster.
+ if (proc.mState.hasShownUi() == hasShownUi) return;
+ proc.mState.setHasShownUi(hasShownUi);
+ }
+
+ /**
+ * Note whether the process has an activity or not.
+ */
+ public void setHasActivity(@NonNull ProcessRecord proc, boolean hasActivity) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ // Possibly not needed, maybe can use ActivityStateFlags.
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Note whether the process has a visibly activity or not.
+ */
+ public void setHasVisibleActivity(@NonNull ProcessRecord proc, boolean hasVisibleActivity) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ // maybe used ActivityStateFlags instead.
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /**
+ * Set the Activity State Flags for a process.
+ */
+ public void setActivityStateFlags(@NonNull ProcessRecord proc, int flags) {
+ // TODO(b/302575389): Migrate state pulled from ATMS to a pushed model
+ throw new UnsupportedOperationException("Not implemented yet");
+ }
+
+ /********************** Content Provider State Events **********************/
+ /**
+ * Note that a process is hosting a content provider.
+ */
+ public boolean addPublishedProvider(@NonNull ProcessRecord proc, String name,
+ ContentProviderRecord cpr) {
+ final ProcessProviderRecord providers = proc.mProviders;
+ if (providers.hasProvider(name)) return false;
+ providers.installProvider(name, cpr);
+ return true;
+ }
+
+ /**
+ * Remove a published content provider from a process.
+ */
+ public void removePublishedProvider(@NonNull ProcessRecord proc, String name) {
+ final ProcessProviderRecord providers = proc.mProviders;
+ providers.removeProvider(name);
+ }
+
+ /**
+ * Note that a content provider has an external client.
+ */
+ public void addExternalProviderClient(@NonNull ContentProviderRecord cpr,
+ IBinder externalProcessToken, int callingUid, String callingTag) {
+ cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+ }
+
+ /**
+ * Remove an external client from a conetnt provider.
+ */
+ public boolean removeExternalProviderClient(@NonNull ContentProviderRecord cpr,
+ IBinder externalProcessToken) {
+ return cpr.removeExternalProcessHandleLocked(externalProcessToken);
+ }
+
+ /**
+ * Note the time a process is no longer hosting any content providers.
+ */
+ public void setLastProviderTime(@NonNull ProcessRecord proc, long uptimeMs) {
+ proc.mProviders.setLastProviderTime(uptimeMs);
+ }
+
+ /**
+ * Note that a process has connected to a content provider.
+ */
+ public void addProviderConnection(@NonNull ProcessRecord client,
+ ContentProviderConnection cpc) {
+ client.mProviders.addProviderConnection(cpc);
+ }
+
+ /**
+ * Note that a process is no longer connected to a content provider.
+ */
+ public void removeProviderConnection(@NonNull ProcessRecord client,
+ ContentProviderConnection cpc) {
+ client.mProviders.addProviderConnection(cpc);
+ }
+
+ /********************** Content Provider State Events **********************/
+ /*************************** Service State Events **************************/
+ /**
+ * Note that a process has started hosting a service.
+ */
+ public boolean startService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+ return psr.startService(sr);
+ }
+
+ /**
+ * Note that a process has stopped hosting a service.
+ */
+ public boolean stopService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+ return psr.stopService(sr);
+ }
+
+ /**
+ * Remove all services that the process is hosting.
+ */
+ public void stopAllServices(@NonNull ProcessServiceRecord psr) {
+ psr.stopAllServices();
+ }
+
+ /**
+ * Note that a process's service has started executing.
+ */
+ public void startExecutingService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+ psr.startExecutingService(sr);
+ }
+
+ /**
+ * Note that a process's service has stopped executing.
+ */
+ public void stopExecutingService(@NonNull ProcessServiceRecord psr, ServiceRecord sr) {
+ psr.stopExecutingService(sr);
+ }
+
+ /**
+ * Note all executing services a process has has stopped.
+ */
+ public void stopAllExecutingServices(@NonNull ProcessServiceRecord psr) {
+ psr.stopAllExecutingServices();
+ }
+
+ /**
+ * Note that process has bound to a service.
+ */
+ public void addConnection(@NonNull ProcessServiceRecord psr, ConnectionRecord cr) {
+ psr.addConnection(cr);
+ }
+
+ /**
+ * Note that process has unbound from a service.
+ */
+ public void removeConnection(@NonNull ProcessServiceRecord psr, ConnectionRecord cr) {
+ psr.removeConnection(cr);
+ }
+
+ /**
+ * Remove all bindings a process has to services.
+ */
+ public void removeAllConnections(@NonNull ProcessServiceRecord psr) {
+ psr.removeAllConnections();
+ psr.removeAllSdkSandboxConnections();
+ }
+
+ /**
+ * Note whether an executing service should be considered in the foreground or not.
+ */
+ public void setExecServicesFg(@NonNull ProcessServiceRecord psr, boolean execServicesFg) {
+ psr.setExecServicesFg(execServicesFg);
+ }
+
+ /**
+ * Note whether a service is in the foreground or not and what type of FGS, if so.
+ */
+ public void setHasForegroundServices(@NonNull ProcessServiceRecord psr,
+ boolean hasForegroundServices,
+ int fgServiceTypes, boolean hasTypeNoneFgs) {
+ psr.setHasForegroundServices(hasForegroundServices, fgServiceTypes, hasTypeNoneFgs);
+ }
+
+ /**
+ * Note whether a service has a client activity or not.
+ */
+ public void setHasClientActivities(@NonNull ProcessServiceRecord psr,
+ boolean hasClientActivities) {
+ psr.setHasClientActivities(hasClientActivities);
+ }
+
+ /**
+ * Note whether a service should be treated like an activity or not.
+ */
+ public void setTreatLikeActivity(@NonNull ProcessServiceRecord psr, boolean treatLikeActivity) {
+ psr.setTreatLikeActivity(treatLikeActivity);
+ }
+
+ /**
+ * Note whether a process has bound to a service with
+ * {@link android.content.Context.BIND_ABOVE_CLIENT} or not.
+ */
+ public void setHasAboveClient(@NonNull ProcessServiceRecord psr, boolean hasAboveClient) {
+ psr.setHasAboveClient(hasAboveClient);
+ }
+
+ /**
+ * Recompute whether a process has bound to a service with
+ * {@link android.content.Context.BIND_ABOVE_CLIENT} or not.
+ */
+ public void updateHasAboveClientLocked(@NonNull ProcessServiceRecord psr) {
+ psr.updateHasAboveClientLocked();
+ }
+
+ /**
+ * Cleanup a process's state.
+ */
+ public void onCleanupApplicationRecord(@NonNull ProcessServiceRecord psr) {
+ psr.onCleanupApplicationRecordLocked();
+ }
+
+ /**
+ * Set which process is hosting a service.
+ */
+ public void setHostProcess(@NonNull ServiceRecord sr, @Nullable ProcessRecord host) {
+ sr.app = host;
+ }
+
+ /**
+ * Note whether a service is a Foreground Service or not
+ */
+ public void setIsForegroundService(@NonNull ServiceRecord sr, boolean isFgs) {
+ sr.isForeground = isFgs;
+ }
+
+ /**
+ * Note the Foreground Service type of a service.
+ */
+ public void setForegroundServiceType(@NonNull ServiceRecord sr,
+ @ServiceInfo.ForegroundServiceType int fgsType) {
+ sr.foregroundServiceType = fgsType;
+ }
+
+ /**
+ * Note the start time of a short foreground service.
+ */
+ public void setShortFgsInfo(@NonNull ServiceRecord sr, long uptimeNow) {
+ sr.setShortFgsInfo(uptimeNow);
+ }
+
+ /**
+ * Note that a short foreground service has stopped.
+ */
+ public void clearShortFgsInfo(@NonNull ServiceRecord sr) {
+ sr.clearShortFgsInfo();
+ }
+
+ /**
+ * Note the last time a service was active.
+ */
+ public void setServiceLastActivityTime(@NonNull ServiceRecord sr, long lastActivityUpdateMs) {
+ sr.lastActivity = lastActivityUpdateMs;
+ }
+
+ /**
+ * Note that a service start was requested.
+ */
+ public void setStartRequested(@NonNull ServiceRecord sr, boolean startRequested) {
+ sr.startRequested = startRequested;
+ }
+
+ /**
+ * Note the last time the service was bound by a Top process with
+ * {@link android.content.Context.BIND_ALMOST_PERCEPTIBLE}
+ */
+ public void setLastTopAlmostPerceptibleBindRequest(@NonNull ServiceRecord sr,
+ long lastTopAlmostPerceptibleBindRequestUptimeMs) {
+ sr.lastTopAlmostPerceptibleBindRequestUptimeMs =
+ lastTopAlmostPerceptibleBindRequestUptimeMs;
+ }
+
+ /**
+ * Recompute whether a process has bound to a service with
+ * {@link android.content.Context.BIND_ALMOST_PERCEPTIBLE} or not.
+ */
+ public void updateHasTopStartedAlmostPerceptibleServices(@NonNull ProcessServiceRecord psr) {
+ psr.updateHasTopStartedAlmostPerceptibleServices();
+ }
+
+ /**
+ * Builder for ProcessStateController.
+ */
+ public static class Builder {
+ private final ActivityManagerService mAms;
+ private final ProcessList mProcessList;
+ private final ActiveUids mActiveUids;
+
+ private ServiceThread mHandlerThread = null;
+ private OomAdjuster.Injector mOomAdjInjector = null;
+ private boolean mUseOomAdjusterModernImpl = false;
+
+ public Builder(ActivityManagerService ams, ProcessList processList, ActiveUids activeUids) {
+ mAms = ams;
+ mProcessList = processList;
+ mActiveUids = activeUids;
+ }
+
+ /**
+ * Build the ProcessStateController object.
+ */
+ public ProcessStateController build() {
+ if (mHandlerThread == null) {
+ mHandlerThread = OomAdjuster.createAdjusterThread();
+ }
+ if (mOomAdjInjector == null) {
+ mOomAdjInjector = new OomAdjuster.Injector();
+ }
+ return new ProcessStateController(mAms, mProcessList, mActiveUids, mHandlerThread,
+ mOomAdjInjector, mUseOomAdjusterModernImpl);
+ }
+
+ /**
+ * For Testing Purposes. Set what thread OomAdjuster will offload tasks on to.
+ */
+ public Builder setHandlerThread(ServiceThread handlerThread) {
+ mHandlerThread = handlerThread;
+ return this;
+ }
+
+ /**
+ * For Testing Purposes. Set an injector for OomAdjuster.
+ */
+ public Builder setOomAdjusterInjector(OomAdjuster.Injector injector) {
+ mOomAdjInjector = injector;
+ return this;
+ }
+
+ /**
+ * Set which implementation of OomAdjuster to use.
+ */
+ public Builder useModernOomAdjuster(boolean use) {
+ mUseOomAdjusterModernImpl = use;
+ return this;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index bc990d9..b0f808b 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -19,14 +19,11 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
-import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_ACTIVITY;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_STARTED_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
-import static com.android.server.am.ProcessRecord.TAG;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING;
import static com.android.server.wm.WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
@@ -38,7 +35,6 @@
import android.content.ComponentName;
import android.os.SystemClock;
import android.os.Trace;
-import android.util.Slog;
import android.util.TimeUtils;
import com.android.internal.annotations.CompositeRWLock;
@@ -790,15 +786,7 @@
@GuardedBy("mService")
void setRunningRemoteAnimation(boolean runningRemoteAnimation) {
- if (mRunningRemoteAnimation == runningRemoteAnimation) {
- return;
- }
mRunningRemoteAnimation = runningRemoteAnimation;
- if (DEBUG_OOM_ADJ) {
- Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
- + " for pid=" + mApp.getPid());
- }
- mService.updateOomAdjLocked(mApp, OOM_ADJ_REASON_UI_VISIBILITY);
}
@GuardedBy({"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index b9cdf27..92d33c9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1248,7 +1248,7 @@
app.mServices.updateBoundClientUids();
app.mServices.updateHostingComonentTypeForBindingsLocked();
}
- app = proc;
+ ams.mProcessStateController.setHostProcess(this, proc);
updateProcessStateOnRequest();
if (pendingConnectionGroup > 0 && proc != null) {
final ProcessServiceRecord psr = proc.mServices;
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 7873d34..adf0e64 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -218,3 +218,10 @@
description: "Set reset_on_fork flag."
bug: "370988407"
}
+
+flag {
+ name: "push_global_state_to_oomadjuster"
+ namespace: "backstage_power"
+ description: "Migrate OomAdjuster pulled device state to a push model"
+ bug: "302575389"
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 596e375..e0cf96f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -72,9 +72,6 @@
import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
import static android.permission.flags.Flags.deviceAwareAppOpNewSchemaEnabled;
-import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION;
-import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_OPERATION;
-import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_PROXY_OPERATION;
import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
import android.Manifest;
@@ -163,7 +160,6 @@
import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -2833,26 +2829,12 @@
@Override
public int checkOperation(int code, int uid, String packageName) {
- if (Flags.appopAccessTrackingLoggingEnabled()) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
- uid, code,
- APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION,
- false);
- }
return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
Context.DEVICE_ID_DEFAULT, false /*raw*/);
}
@Override
public int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId) {
- if (Flags.appopAccessTrackingLoggingEnabled()) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
- uid, code,
- APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION,
- false);
- }
return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
virtualDeviceId, false /*raw*/);
}
@@ -3033,14 +3015,6 @@
public SyncNotedAppOp noteProxyOperationWithState(int code,
AttributionSourceState attributionSourceState, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage, boolean skipProxyOperation) {
- if (Flags.appopAccessTrackingLoggingEnabled()) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
- attributionSourceState.uid, code,
- APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_PROXY_OPERATION,
- attributionSourceState.attributionTag != null);
- }
-
AttributionSource attributionSource = new AttributionSource(attributionSourceState);
return mCheckOpsDelegateDispatcher.noteProxyOperation(code, attributionSource,
shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation);
@@ -3122,14 +3096,6 @@
public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
String attributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
- if (Flags.appopAccessTrackingLoggingEnabled()) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED,
- uid, code,
- APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__NOTE_OPERATION,
- attributionTag != null);
- }
-
return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message,
shouldCollectMessage);
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 1094bee..6216a58 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -785,8 +785,8 @@
+ " IDeviceStateManagerCallback.");
}
- ProcessRecord record = new ProcessRecord(callback, pid, this::handleProcessDied,
- mHandler);
+ final ProcessRecord record =
+ new ProcessRecord(callback, pid, this::handleProcessDied, mHandler);
try {
callback.asBinder().linkToDeath(record, 0);
} catch (RemoteException ex) {
@@ -797,8 +797,8 @@
// Callback clients should not be notified of invalid device states, so calls to
// #getDeviceStateInfoLocked should be gated on checks if a committed state is present
// before getting the device state info.
- DeviceStateInfo currentInfo = mCommittedState.isPresent()
- ? getDeviceStateInfoLocked() : null;
+ final DeviceStateInfo currentInfo =
+ mCommittedState.isPresent() ? getDeviceStateInfoLocked() : null;
if (currentInfo != null) {
// If there is not a committed state we'll wait to notify the process of the initial
// value.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d71826f..179ec63 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1978,7 +1978,7 @@
// handles stopping the projection.
Slog.w(TAG, "Content Recording: failed to start mirroring - "
+ "releasing virtual display " + displayId);
- releaseVirtualDisplayInternal(callback.asBinder());
+ releaseVirtualDisplayInternal(callback.asBinder(), callingUid);
return Display.INVALID_DISPLAY;
} else if (projection != null) {
// Indicate that this projection has been used to record, and can't be used
@@ -2067,7 +2067,7 @@
// Something weird happened and the logical display was not created.
Slog.w(TAG, "Rejecting request to create virtual display "
+ "because the logical display was not created.");
- mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
+ mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder(), callingUid);
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
return -1;
@@ -2094,14 +2094,14 @@
}
}
- private void releaseVirtualDisplayInternal(IBinder appToken) {
+ private void releaseVirtualDisplayInternal(IBinder appToken, int callingUid) {
synchronized (mSyncRoot) {
if (mVirtualDisplayAdapter == null) {
return;
}
DisplayDevice device =
- mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+ mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken, callingUid);
Slog.d(TAG, "Virtual Display: Display Device released");
if (device != null) {
// TODO: multi-display - handle virtual displays the same as other display adapters.
@@ -4620,9 +4620,10 @@
@Override // Binder call
public void releaseVirtualDisplay(IVirtualDisplayCallback callback) {
+ final int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- releaseVirtualDisplayInternal(callback.asBinder());
+ releaseVirtualDisplayInternal(callback.asBinder(), callingUid);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index e77c5ec..4211453 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -55,12 +55,14 @@
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayShape;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -85,6 +87,11 @@
private static final AtomicInteger sNextUniqueIndex = new AtomicInteger(0);
private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = new ArrayMap<>();
+
+ private final int mMaxDevices;
+ private final int mMaxDevicesPerPackage;
+ private final SparseIntArray mNoOfDevicesPerPackage = new SparseIntArray();
+
private final Handler mHandler;
private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory;
@@ -114,8 +121,31 @@
super(syncRoot, context, handler, listener, TAG, featureFlags);
mHandler = handler;
mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
+
+ mMaxDevices = context.getResources().getInteger(R.integer.config_virtualDisplayLimit);
+ if (mMaxDevices < 1) {
+ throw new IllegalArgumentException("The limit of virtual displays must be >= 1");
+ }
+ mMaxDevicesPerPackage =
+ context.getResources().getInteger(R.integer.config_virtualDisplayLimitPerPackage);
+ if (mMaxDevicesPerPackage < 1) {
+ throw new IllegalArgumentException(
+ "The limit of virtual displays per package must be >= 1");
+ }
}
+ /**
+ * Create a virtual display
+ * @param callback The callback
+ * @param projection The media projection
+ * @param ownerUid The UID of the package creating a display
+ * @param ownerPackageName The name of the package creating a display
+ * @param uniqueId The unique ID of the display device
+ * @param surface The surface
+ * @param flags The flags
+ * @param virtualDisplayConfig The config
+ * @return The display device created
+ */
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, int ownerUid, String ownerPackageName, String uniqueId,
Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) {
@@ -126,6 +156,22 @@
return null;
}
+ if (getFeatureFlags().isVirtualDisplayLimitEnabled()
+ && mVirtualDisplayDevices.size() >= mMaxDevices) {
+ Slog.w(TAG, "Rejecting request to create private virtual display because "
+ + mMaxDevices + " devices already exist.");
+ return null;
+ }
+
+ int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0);
+ if (getFeatureFlags().isVirtualDisplayLimitEnabled()
+ && noOfDevices >= mMaxDevicesPerPackage) {
+ Slog.w(TAG, "Rejecting request to create private virtual display because "
+ + mMaxDevicesPerPackage + " devices already exist for package "
+ + ownerPackageName + ".");
+ return null;
+ }
+
String name = virtualDisplayConfig.getName();
boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
@@ -140,6 +186,9 @@
projection, mediaProjectionCallback, uniqueId, virtualDisplayConfig);
mVirtualDisplayDevices.put(appToken, device);
+ if (getFeatureFlags().isVirtualDisplayLimitEnabled()) {
+ mNoOfDevicesPerPackage.put(ownerUid, noOfDevices + 1);
+ }
try {
if (projection != null) {
@@ -150,7 +199,7 @@
appToken.linkToDeath(device, 0);
} catch (RemoteException ex) {
Slog.e(TAG, "Virtual Display: error while setting up VirtualDisplayDevice", ex);
- mVirtualDisplayDevices.remove(appToken);
+ removeVirtualDisplayDeviceLocked(appToken, ownerUid);
device.destroyLocked(false);
return null;
}
@@ -194,8 +243,15 @@
}
}
- public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
- VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
+ /**
+ * Release a virtual display that was previously created
+ * @param appToken The token to identify the display
+ * @param ownerUid The UID of the package, used to keep track of and limit the number of
+ * displays created per package
+ * @return The display device that has been removed
+ */
+ public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken, int ownerUid) {
+ VirtualDisplayDevice device = removeVirtualDisplayDeviceLocked(appToken, ownerUid);
if (device != null) {
Slog.v(TAG, "Release VirtualDisplay " + device.mName);
device.destroyLocked(true);
@@ -228,10 +284,6 @@
: ("," + uid + "," + config.getName() + "," + sNextUniqueIndex.getAndIncrement()));
}
- private void handleBinderDiedLocked(IBinder appToken) {
- mVirtualDisplayDevices.remove(appToken);
- }
-
private void handleMediaProjectionStoppedLocked(IBinder appToken) {
VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
if (device != null) {
@@ -241,6 +293,18 @@
}
}
+ private VirtualDisplayDevice removeVirtualDisplayDeviceLocked(IBinder appToken, int ownerUid) {
+ int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0);
+ if (getFeatureFlags().isVirtualDisplayLimitEnabled()) {
+ if (noOfDevices <= 1) {
+ mNoOfDevicesPerPackage.delete(ownerUid);
+ } else {
+ mNoOfDevicesPerPackage.put(ownerUid, noOfDevices - 1);
+ }
+ }
+ return mVirtualDisplayDevices.remove(appToken);
+ }
+
private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
private static final int PENDING_SURFACE_CHANGE = 0x01;
private static final int PENDING_RESIZE = 0x02;
@@ -300,7 +364,7 @@
@Override
public void binderDied() {
synchronized (getSyncRoot()) {
- handleBinderDiedLocked(mAppToken);
+ removeVirtualDisplayDeviceLocked(mAppToken, mOwnerUid);
Slog.i(TAG, "Virtual display device released because application token died: "
+ mOwnerPackageName);
destroyLocked(false);
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 5284d1c..99ced7f 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -199,6 +199,11 @@
Flags.FLAG_IDLE_SCREEN_CONFIG_IN_SUBSCRIBING_LIGHT_SENSOR,
Flags::idleScreenConfigInSubscribingLightSensor);
+ private final FlagState mVirtualDisplayLimit =
+ new FlagState(
+ Flags.FLAG_VIRTUAL_DISPLAY_LIMIT,
+ Flags::virtualDisplayLimit);
+
private final FlagState mNormalBrightnessForDozeParameter = new FlagState(
Flags.FLAG_NORMAL_BRIGHTNESS_FOR_DOZE_PARAMETER,
Flags::normalBrightnessForDozeParameter
@@ -207,6 +212,10 @@
Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE,
Flags::blockAutobrightnessChangesOnStylusUsage
);
+ private final FlagState mIsUserRefreshRateForExternalDisplayEnabled = new FlagState(
+ Flags.FLAG_ENABLE_USER_REFRESH_RATE_FOR_EXTERNAL_DISPLAY,
+ Flags::enableUserRefreshRateForExternalDisplay
+ );
private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState(
Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
@@ -416,6 +425,10 @@
return mNewHdrBrightnessModifier.isEnabled();
}
+ public boolean isVirtualDisplayLimitEnabled() {
+ return mVirtualDisplayLimit.isEnabled();
+ }
+
/**
* @return Whether the useDozeBrightness parameter should be used
*/
@@ -447,6 +460,14 @@
}
/**
+ * @return {@code true} if need to use user refresh rate settings for
+ * external displays.
+ */
+ public boolean isUserRefreshRateForExternalDisplayEnabled() {
+ return mIsUserRefreshRateForExternalDisplayEnabled.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -487,10 +508,12 @@
pw.println(" " + mOffloadDozeOverrideHoldsWakelock);
pw.println(" " + mOffloadSessionCancelBlockScreenOn);
pw.println(" " + mNewHdrBrightnessModifier);
+ pw.println(" " + mVirtualDisplayLimit);
pw.println(" " + mNormalBrightnessForDozeParameter);
pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
pw.println(" " + mEnableBatteryStatsForAllDisplays);
pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage);
+ pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 252ed09..2f04d9e 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -348,6 +348,14 @@
}
flag {
+ name: "virtual_display_limit"
+ namespace: "display_manager"
+ description: "Limit the number of virtual displays that can be created."
+ bug: "261791612"
+ is_fixed_read_only: true
+}
+
+flag {
name: "idle_screen_config_in_subscribing_light_sensor"
namespace: "display_manager"
description: "Account for Idle screen refresh rate configs while subscribing to light sensor"
@@ -373,3 +381,14 @@
bug: "352411468"
is_fixed_read_only: true
}
+
+flag {
+ name: "enable_user_refresh_rate_for_external_display"
+ namespace: "display_manager"
+ description: "Apply refresh rate from user preferred display mode to external displays"
+ bug: "370657357"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 18e0d6e..ffa64bf 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -1194,6 +1194,13 @@
@GuardedBy("mLock")
private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
float defaultRefreshRate, int displayId) {
+ if (mDisplayObserver.isExternalDisplayLocked(displayId)) {
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "skip updateRefreshRateSettingLocked for external display "
+ + displayId);
+ }
+ return;
+ }
// TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
// used to predict if we're going to be doing frequent refresh rate switching, and if
// so, enable the brightness observer. The logic here is more complicated and fragile
@@ -1243,6 +1250,8 @@
}
private void removeRefreshRateSetting(int displayId) {
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
+ null);
mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
null);
mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
@@ -1458,11 +1467,11 @@
public void onDisplayAdded(int displayId) {
updateDisplayDeviceConfig(displayId);
DisplayInfo displayInfo = getDisplayInfo(displayId);
+ registerExternalDisplay(displayInfo);
updateDisplayModes(displayId, displayInfo);
updateLayoutLimitedFrameRate(displayId, displayInfo);
updateUserSettingDisplayPreferredSize(displayInfo);
updateDisplaysPeakRefreshRateAndResolution(displayInfo);
- addDisplaysSynchronizedPeakRefreshRate(displayInfo);
}
@Override
@@ -1477,7 +1486,7 @@
updateLayoutLimitedFrameRate(displayId, null);
removeUserSettingDisplayPreferredSize(displayId);
removeDisplaysPeakRefreshRateAndResolution(displayId);
- removeDisplaysSynchronizedPeakRefreshRate(displayId);
+ unregisterExternalDisplay(displayId);
}
@Override
@@ -1489,6 +1498,30 @@
updateUserSettingDisplayPreferredSize(displayInfo);
}
+ private void registerExternalDisplay(DisplayInfo displayInfo) {
+ if (displayInfo == null || displayInfo.type != Display.TYPE_EXTERNAL) {
+ return;
+ }
+ synchronized (mLock) {
+ mExternalDisplaysConnected.add(displayInfo.displayId);
+ if (mExternalDisplaysConnected.size() == 1) {
+ addDisplaysSynchronizedPeakRefreshRate();
+ }
+ }
+ }
+
+ private void unregisterExternalDisplay(int displayId) {
+ synchronized (mLock) {
+ if (!isExternalDisplayLocked(displayId)) {
+ return;
+ }
+ mExternalDisplaysConnected.remove(displayId);
+ if (mExternalDisplaysConnected.isEmpty()) {
+ removeDisplaysSynchronizedPeakRefreshRate();
+ }
+ }
+ }
+
boolean isExternalDisplayLocked(int displayId) {
return mExternalDisplaysConnected.contains(displayId);
}
@@ -1534,10 +1567,24 @@
return;
}
- mVotesStorage.updateVote(info.displayId,
- Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
- Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
- /* height */ preferredMode.getPhysicalHeight()));
+ if (info.type == Display.TYPE_EXTERNAL
+ && mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()
+ && !isRefreshRateSynchronizationEnabled()) {
+ mVotesStorage.updateVote(info.displayId,
+ Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
+ Vote.forSizeAndPhysicalRefreshRatesRange(
+ /* minWidth */ preferredMode.getPhysicalWidth(),
+ /* minHeight */ preferredMode.getPhysicalHeight(),
+ /* width */ preferredMode.getPhysicalWidth(),
+ /* height */ preferredMode.getPhysicalHeight(),
+ /* minRefreshRate */ preferredMode.getRefreshRate(),
+ /* maxRefreshRate */ preferredMode.getRefreshRate()));
+ } else {
+ mVotesStorage.updateVote(info.displayId,
+ Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
+ Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
+ /* height */ preferredMode.getPhysicalHeight()));
+ }
}
@Nullable
@@ -1584,17 +1631,10 @@
* Sets 60Hz target refresh rate as the vote with
* {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority.
*/
- private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) {
- if (info == null || info.type != Display.TYPE_EXTERNAL
- || !isRefreshRateSynchronizationEnabled()) {
+ private void addDisplaysSynchronizedPeakRefreshRate() {
+ if (!isRefreshRateSynchronizationEnabled()) {
return;
}
- synchronized (mLock) {
- mExternalDisplaysConnected.add(info.displayId);
- if (mExternalDisplaysConnected.size() != 1) {
- return;
- }
- }
// set minRefreshRate as the max refresh rate.
mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE,
Vote.forPhysicalRefreshRates(
@@ -1610,19 +1650,10 @@
+ SYNCHRONIZED_REFRESH_RATE_TOLERANCE));
}
- private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) {
+ private void removeDisplaysSynchronizedPeakRefreshRate() {
if (!isRefreshRateSynchronizationEnabled()) {
return;
}
- synchronized (mLock) {
- if (!isExternalDisplayLocked(displayId)) {
- return;
- }
- mExternalDisplaysConnected.remove(displayId);
- if (!mExternalDisplaysConnected.isEmpty()) {
- return;
- }
- }
mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null);
mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null);
}
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index 459f9a6..f5abb05 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -44,7 +44,7 @@
// It votes [minRefreshRate, Float.POSITIVE_INFINITY]
int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
- // User setting preferred display resolution.
+ // User setting preferred display resolution, for external displays also includes refresh rate.
int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;
// APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 8b06dad..d1d5d48 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1112,19 +1112,12 @@
continue;
}
- Log.w(
- TAG,
- TextUtils.formatSimple(
- "Revoking access to manager record id: %d, package: %s, userId:"
- + " %d",
- manager.mManagerId, manager.mOwnerPackageName, userRecord.mUserId));
-
+ Slog.w(TAG, "Revoking access for " + manager.getDebugString());
unregisterManagerLocked(manager.mManager, /* died */ false);
-
try {
manager.mManager.invalidateInstance();
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify manager= " + manager + " of permission revocation.");
+ manager.logRemoteException("invalidateInstance", ex);
}
}
}
@@ -2428,10 +2421,7 @@
try {
mManager.notifyRequestFailed(requestId, reason);
} catch (RemoteException ex) {
- Slog.w(
- TAG,
- "Failed to notify manager of the request failure. Manager probably died.",
- ex);
+ logRemoteException("notifyRequestFailed", ex);
}
}
@@ -2444,7 +2434,7 @@
try {
mManager.notifyRoutesUpdated(routes);
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify routes. Manager probably died.", ex);
+ logRemoteException("notifyRoutesUpdated", ex);
}
}
@@ -2457,10 +2447,7 @@
try {
mManager.notifySessionUpdated(sessionInfo);
} catch (RemoteException ex) {
- Slog.w(
- TAG,
- "notifySessionUpdatedToManagers: Failed to notify. Manager probably died.",
- ex);
+ logRemoteException("notifySessionUpdated", ex);
}
}
@@ -2473,13 +2460,18 @@
try {
mManager.notifySessionReleased(sessionInfo);
} catch (RemoteException ex) {
- Slog.w(
- TAG,
- "notifySessionReleasedToManagers: Failed to notify. Manager probably died.",
- ex);
+ logRemoteException("notifySessionReleased", ex);
}
}
+ private void logRemoteException(String operation, RemoteException exception) {
+ String message =
+ TextUtils.formatSimple(
+ "%s failed for %s due to %s",
+ operation, getDebugString(), exception.toString());
+ Slog.w(TAG, message);
+ }
+
private void updateScanningState(@ScanningState int scanningState) {
if (mScanningState == scanningState) {
return;
@@ -2492,9 +2484,16 @@
UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
}
- @Override
- public String toString() {
- return "Manager " + mOwnerPackageName + " (pid " + mOwnerPid + ")";
+ /** Returns a human readable representation of this manager record for logging purposes. */
+ public String getDebugString() {
+ return TextUtils.formatSimple(
+ "Manager %s (id=%d,pid=%d,userId=%d,uid=%d,targetPkg=%s)",
+ mOwnerPackageName,
+ mManagerId,
+ mOwnerPid,
+ mUserRecord.mUserId,
+ mOwnerUid,
+ mTargetPackageName);
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index cd0a2a7..03fc60c 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -106,8 +106,7 @@
protected final String TAG = getClass().getSimpleName().replace('$', '.');
protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- protected static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
- protected static final int ON_BINDING_DIED_REBIND_MSG = 1234;
+ private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
protected static final String ENABLED_SERVICES_SEPARATOR = ":";
private static final String DB_VERSION_1 = "1";
private static final String DB_VERSION_2 = "2";
@@ -857,13 +856,7 @@
String approvedItem = getApprovedValue(pkgOrComponent);
if (approvedItem != null) {
- final ComponentName component = ComponentName.unflattenFromString(approvedItem);
if (enabled) {
- if (component != null && !isValidService(component, userId)) {
- Log.e(TAG, "Skip allowing " + mConfig.caption + " " + pkgOrComponent
- + " (userSet: " + userSet + ") for invalid service");
- return;
- }
approved.add(approvedItem);
} else {
approved.remove(approvedItem);
@@ -961,7 +954,7 @@
|| isPackageOrComponentAllowed(component.getPackageName(), userId))) {
return false;
}
- return isValidService(component, userId);
+ return componentHasBindPermission(component, userId);
}
private boolean componentHasBindPermission(ComponentName component, int userId) {
@@ -1313,12 +1306,11 @@
if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
final ComponentName component = ComponentName.unflattenFromString(
approvedPackageOrComponent);
- if (component != null && !isValidService(component, userId)) {
+ if (component != null && !componentHasBindPermission(component, userId)) {
approved.removeAt(j);
if (DEBUG) {
Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no bind permission or "
- + "service interface filter found "
+ + " from approved list; no bind permission found "
+ mConfig.bindPermission);
}
}
@@ -1337,11 +1329,6 @@
}
}
- protected boolean isValidService(ComponentName component, int userId) {
- return componentHasBindPermission(component, userId) && queryPackageForServices(
- component.getPackageName(), userId).contains(component);
- }
-
protected boolean isValidEntry(String packageOrComponent, int userId) {
return hasMatchingServices(packageOrComponent, userId);
}
@@ -1499,25 +1486,23 @@
* Called when user switched to unbind all services from other users.
*/
@VisibleForTesting
- void unbindOtherUserServices(int switchedToUser) {
+ void unbindOtherUserServices(int currentUser) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
- t.traceBegin("ManagedServices.unbindOtherUserServices_current" + switchedToUser);
- unbindServicesImpl(switchedToUser, true /* allExceptUser */);
+ t.traceBegin("ManagedServices.unbindOtherUserServices_current" + currentUser);
+ unbindServicesImpl(currentUser, true /* allExceptUser */);
t.traceEnd();
}
- void unbindUserServices(int removedUser) {
+ void unbindUserServices(int user) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
- t.traceBegin("ManagedServices.unbindUserServices" + removedUser);
- unbindServicesImpl(removedUser, false /* allExceptUser */);
+ t.traceBegin("ManagedServices.unbindUserServices" + user);
+ unbindServicesImpl(user, false /* allExceptUser */);
t.traceEnd();
}
void unbindServicesImpl(int user, boolean allExceptUser) {
final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
synchronized (mMutex) {
- // Remove enqueued rebinds to avoid rebinding services for a switched user
- mHandler.removeMessages(ON_BINDING_DIED_REBIND_MSG);
final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
for (ManagedServiceInfo info : removableBoundServices) {
if ((allExceptUser && (info.userid != user))
@@ -1712,7 +1697,6 @@
mServicesRebinding.add(servicesBindingTag);
mHandler.postDelayed(() ->
reregisterService(name, userid),
- ON_BINDING_DIED_REBIND_MSG,
ON_BINDING_DIED_REBIND_DELAY_MS);
} else {
Slog.v(TAG, getCaption() + " not rebinding in user " + userid
diff --git a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
index fd60e06..db57d11 100644
--- a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
+++ b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
@@ -47,6 +47,9 @@
Flags::perDisplayWakeByTouch
);
+ private final FlagState mFrameworkWakelockInfo =
+ new FlagState(Flags.FLAG_FRAMEWORK_WAKELOCK_INFO, Flags::frameworkWakelockInfo);
+
/** Returns whether early-screen-timeout-detector is enabled on not. */
public boolean isEarlyScreenTimeoutDetectorEnabled() {
return mEarlyScreenTimeoutDetectorFlagState.isEnabled();
@@ -67,6 +70,13 @@
}
/**
+ * @return Whether FrameworkWakelockInfo atom logging is enabled or not.
+ */
+ public boolean isFrameworkWakelockInfoEnabled() {
+ return mFrameworkWakelockInfo.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -75,6 +85,7 @@
pw.println(" " + mEarlyScreenTimeoutDetectorFlagState);
pw.println(" " + mImproveWakelockLatency);
pw.println(" " + mPerDisplayWakeByTouch);
+ pw.println(" " + mFrameworkWakelockInfo);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/power/feature/power_flags.aconfig b/services/core/java/com/android/server/power/feature/power_flags.aconfig
index 9cf3bb6..8bb69ba 100644
--- a/services/core/java/com/android/server/power/feature/power_flags.aconfig
+++ b/services/core/java/com/android/server/power/feature/power_flags.aconfig
@@ -26,3 +26,10 @@
bug: "343295183"
is_fixed_read_only: true
}
+
+flag {
+ name: "framework_wakelock_info"
+ namespace: "power"
+ description: "Feature flag to enable statsd pulling of FrameworkWakelockInfo atoms"
+ bug: "352602149"
+}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 936fadf..391071f 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -145,6 +145,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.power.feature.PowerManagerFlags;
import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
import com.android.server.power.stats.format.MobileRadioPowerStatsLayout;
@@ -5142,6 +5143,10 @@
mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name,
uidStats.mProcessState, true /* acquired */,
getPowerManagerWakeLockLevel(type));
+ if (mPowerManagerFlags.isFrameworkWakelockInfoEnabled()) {
+ mFrameworkEvents.noteStartWakeLock(
+ mapIsolatedUid(uid), name, getPowerManagerWakeLockLevel(type), uptimeMs);
+ }
}
}
@@ -5187,6 +5192,10 @@
mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name,
uidStats.mProcessState, false/* acquired */,
getPowerManagerWakeLockLevel(type));
+ if (mPowerManagerFlags.isFrameworkWakelockInfoEnabled()) {
+ mFrameworkEvents.noteStopWakeLock(
+ mapIsolatedUid(uid), name, getPowerManagerWakeLockLevel(type), uptimeMs);
+ }
if (mappedUid != uid) {
// Decrement the ref count for the isolated uid and delete the mapping if uneeded.
@@ -11343,6 +11352,9 @@
return mTmpCpuTimeInFreq;
}
+ WakelockStatsFrameworkEvents mFrameworkEvents = new WakelockStatsFrameworkEvents();
+ PowerManagerFlags mPowerManagerFlags = new PowerManagerFlags();
+
public BatteryStatsImpl(@NonNull BatteryStatsConfig config, @NonNull Clock clock,
@NonNull MonotonicClock monotonicClock, @Nullable File systemDir,
@NonNull Handler handler, @Nullable PlatformIdleStateCallback platformIdleStateCallback,
@@ -15964,6 +15976,10 @@
// Already plugged in. Schedule the long plug in alarm.
scheduleNextResetWhilePluggedInCheck();
}
+
+ if (mPowerManagerFlags.isFrameworkWakelockInfoEnabled()) {
+ mFrameworkEvents.initialize(context);
+ }
}
}
@@ -16791,7 +16807,8 @@
}
int NSORPMS = in.readInt();
if (NSORPMS > 10000) {
- throw new ParcelFormatException("File corrupt: too many screen-off rpm stats " + NSORPMS);
+ throw new ParcelFormatException(
+ "File corrupt: too many screen-off rpm stats " + NSORPMS);
}
for (int irpm = 0; irpm < NSORPMS; irpm++) {
if (in.readInt() != 0) {
diff --git a/services/core/java/com/android/server/power/stats/WakelockStatsFrameworkEvents.java b/services/core/java/com/android/server/power/stats/WakelockStatsFrameworkEvents.java
new file mode 100644
index 0000000..c9693bd
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/WakelockStatsFrameworkEvents.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2024 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.server.power.stats;
+
+import android.app.StatsManager;
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.StatsEvent;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ConcurrentUtils;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** A class to initialise and log metrics pulled by statsd. */
+public class WakelockStatsFrameworkEvents {
+ // statsd has a dimensional limit on the number of different keys it can handle.
+ // Beyond that limit, statsd will drop data.
+ //
+ // When we have seem SUMMARY_THRESHOLD distinct (uid, tag, wakeLockLevel) keys,
+ // we start summarizing new keys as (uid, OVERFLOW_TAG, OVERFLOW_LEVEL) to
+ // reduce the number of keys we pass to statsd.
+ //
+ // When we reach MAX_WAKELOCK_DIMENSIONS distinct keys, we summarize all new keys
+ // as (OVERFLOW_UID, HARD_CAP_TAG, OVERFLOW_LEVEL) to hard cap the number of
+ // distinct keys we pass to statsd.
+ @VisibleForTesting public static final int SUMMARY_THRESHOLD = 500;
+ @VisibleForTesting public static final int MAX_WAKELOCK_DIMENSIONS = 1000;
+
+ @VisibleForTesting public static final int HARD_CAP_UID = -1;
+ @VisibleForTesting public static final String OVERFLOW_TAG = "*overflow*";
+ @VisibleForTesting public static final String HARD_CAP_TAG = "*overflow hard cap*";
+ @VisibleForTesting public static final int OVERFLOW_LEVEL = 1;
+
+ private static class WakeLockKey {
+ private int uid;
+ private String tag;
+ private int powerManagerWakeLockLevel;
+ private int hashCode;
+
+ WakeLockKey(int uid, String tag, int powerManagerWakeLockLevel) {
+ this.uid = uid;
+ this.tag = new String(tag);
+ this.powerManagerWakeLockLevel = powerManagerWakeLockLevel;
+
+ this.hashCode = Objects.hash(uid, tag, powerManagerWakeLockLevel);
+ }
+
+ int getUid() {
+ return uid;
+ }
+
+ String getTag() {
+ return tag;
+ }
+
+ int getPowerManagerWakeLockLevel() {
+ return powerManagerWakeLockLevel;
+ }
+
+ void setOverflow() {
+ tag = OVERFLOW_TAG;
+ powerManagerWakeLockLevel = OVERFLOW_LEVEL;
+ this.hashCode = Objects.hash(uid, tag, powerManagerWakeLockLevel);
+ }
+
+ void setHardCap() {
+ uid = HARD_CAP_UID;
+ tag = HARD_CAP_TAG;
+ powerManagerWakeLockLevel = OVERFLOW_LEVEL;
+ this.hashCode = Objects.hash(uid, tag, powerManagerWakeLockLevel);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof WakeLockKey)) return false;
+
+ WakeLockKey that = (WakeLockKey) o;
+ return uid == that.uid
+ && tag.equals(that.tag)
+ && powerManagerWakeLockLevel == that.powerManagerWakeLockLevel;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.hashCode;
+ }
+ }
+
+ private static class WakeLockStats {
+ // accumulated uptime attributed to this WakeLock since boot, where overlap
+ // (including nesting) is ignored
+ public long uptimeMillis = 0;
+
+ // count of WakeLocks that have been acquired and then released
+ public long completedCount = 0;
+ }
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final Map<WakeLockKey, WakeLockStats> mWakeLockStats = new HashMap<>();
+
+ private static class WakeLockData {
+ // uptime millis when first acquired
+ public long acquireUptimeMillis = 0;
+ public int refCount = 0;
+
+ WakeLockData(long uptimeMillis) {
+ acquireUptimeMillis = uptimeMillis;
+ }
+ }
+
+ @GuardedBy("mLock")
+ private final Map<WakeLockKey, WakeLockData> mOpenWakeLocks = new HashMap<>();
+
+ public void noteStartWakeLock(
+ int uid, String tag, int powerManagerWakeLockLevel, long eventUptimeMillis) {
+ final WakeLockKey key = new WakeLockKey(uid, tag, powerManagerWakeLockLevel);
+
+ synchronized (mLock) {
+ WakeLockData data =
+ mOpenWakeLocks.computeIfAbsent(key, k -> new WakeLockData(eventUptimeMillis));
+ data.refCount++;
+ mOpenWakeLocks.put(key, data);
+ }
+ }
+
+ @VisibleForTesting
+ public boolean inOverflow() {
+ synchronized (mLock) {
+ return inOverflowLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean inOverflowLocked() {
+ return mWakeLockStats.size() >= SUMMARY_THRESHOLD;
+ }
+
+ @VisibleForTesting
+ public boolean inHardCap() {
+ synchronized (mLock) {
+ return inHardCapLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean inHardCapLocked() {
+ return mWakeLockStats.size() >= MAX_WAKELOCK_DIMENSIONS;
+ }
+
+ public void noteStopWakeLock(
+ int uid, String tag, int powerManagerWakeLockLevel, long eventUptimeMillis) {
+ WakeLockKey key = new WakeLockKey(uid, tag, powerManagerWakeLockLevel);
+
+ synchronized (mLock) {
+ WakeLockData data = mOpenWakeLocks.get(key);
+ if (data == null) {
+ Log.e(TAG, "WakeLock not found when stopping: " + uid + " " + tag);
+ return;
+ }
+
+ if (data.refCount == 1) {
+ mOpenWakeLocks.remove(key);
+ long wakeLockDur = eventUptimeMillis - data.acquireUptimeMillis;
+
+ // Rewrite key if in an overflow state.
+ if (inOverflowLocked() && !mWakeLockStats.containsKey(key)) {
+ key.setOverflow();
+ if (inHardCapLocked() && !mWakeLockStats.containsKey(key)) {
+ key.setHardCap();
+ }
+ }
+
+ WakeLockStats stats = mWakeLockStats.computeIfAbsent(key, k -> new WakeLockStats());
+ stats.uptimeMillis += wakeLockDur;
+ stats.completedCount++;
+ mWakeLockStats.put(key, stats);
+ } else {
+ data.refCount--;
+ mOpenWakeLocks.put(key, data);
+ }
+ }
+ }
+
+ public List<StatsEvent> pullFrameworkWakelockInfoAtoms() {
+ return pullFrameworkWakelockInfoAtoms(SystemClock.uptimeMillis());
+ }
+
+ public List<StatsEvent> pullFrameworkWakelockInfoAtoms(long nowMillis) {
+ List<StatsEvent> result = new ArrayList<>();
+ HashSet<WakeLockKey> keys = new HashSet<>();
+
+ // Used to collect open WakeLocks when in an overflow state.
+ HashMap<WakeLockKey, WakeLockStats> openOverflowStats = new HashMap<>();
+
+ synchronized (mLock) {
+ keys.addAll(mWakeLockStats.keySet());
+
+ // If we are in an overflow state, an open wakelock may have a new key
+ // that needs to be summarized.
+ if (inOverflowLocked()) {
+ for (WakeLockKey key : mOpenWakeLocks.keySet()) {
+ if (!mWakeLockStats.containsKey(key)) {
+ WakeLockData data = mOpenWakeLocks.get(key);
+
+ key.setOverflow();
+ if (inHardCapLocked() && !mWakeLockStats.containsKey(key)) {
+ key.setHardCap();
+ }
+ keys.add(key);
+
+ WakeLockStats stats =
+ openOverflowStats.computeIfAbsent(key, k -> new WakeLockStats());
+ stats.uptimeMillis += nowMillis - data.acquireUptimeMillis;
+ openOverflowStats.put(key, stats);
+ }
+ }
+ } else {
+ keys.addAll(mOpenWakeLocks.keySet());
+ }
+
+ for (WakeLockKey key : keys) {
+ long openWakeLockUptime = 0;
+ WakeLockData data = mOpenWakeLocks.get(key);
+ if (data != null) {
+ openWakeLockUptime = nowMillis - data.acquireUptimeMillis;
+ }
+
+ WakeLockStats stats = mWakeLockStats.computeIfAbsent(key, k -> new WakeLockStats());
+ WakeLockStats extraTime =
+ openOverflowStats.computeIfAbsent(key, k -> new WakeLockStats());
+
+ stats.uptimeMillis += openWakeLockUptime + extraTime.uptimeMillis;
+
+ StatsEvent event =
+ StatsEvent.newBuilder()
+ .setAtomId(FrameworkStatsLog.FRAMEWORK_WAKELOCK_INFO)
+ .writeInt(key.getUid())
+ .writeString(key.getTag())
+ .writeInt(key.getPowerManagerWakeLockLevel())
+ .writeLong(stats.uptimeMillis)
+ .writeLong(stats.completedCount)
+ .build();
+ result.add(event);
+ }
+ }
+
+ return result;
+ }
+
+ private static final String TAG = "BatteryStatsPulledMetrics";
+
+ private final StatsPullCallbackHandler mStatsPullCallbackHandler =
+ new StatsPullCallbackHandler();
+
+ private boolean mIsInitialized = false;
+
+ public void initialize(Context context) {
+ if (mIsInitialized) {
+ return;
+ }
+
+ final StatsManager statsManager = context.getSystemService(StatsManager.class);
+ if (statsManager == null) {
+ Log.e(
+ TAG,
+ "Error retrieving StatsManager. Cannot initialize BatteryStatsPulledMetrics.");
+ } else {
+ Log.d(TAG, "Registering callback with StatsManager");
+
+ // DIRECT_EXECUTOR means that callback will run on binder thread.
+ statsManager.setPullAtomCallback(
+ FrameworkStatsLog.FRAMEWORK_WAKELOCK_INFO,
+ null /* metadata */,
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ mStatsPullCallbackHandler);
+ mIsInitialized = true;
+ }
+ }
+
+ private class StatsPullCallbackHandler implements StatsManager.StatsPullAtomCallback {
+ @Override
+ public int onPullAtom(int atomTag, List<StatsEvent> data) {
+ // handle the tags appropriately.
+ List<StatsEvent> events = pullEvents(atomTag);
+ if (events == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ data.addAll(events);
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ private List<StatsEvent> pullEvents(int atomTag) {
+ switch (atomTag) {
+ case FrameworkStatsLog.FRAMEWORK_WAKELOCK_INFO:
+ return pullFrameworkWakelockInfoAtoms();
+ default:
+ return null;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 74c1124e..e7735d8 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -63,6 +63,7 @@
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__UNKNOWN;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.stats.Flags.accumulateNetworkStatsSinceBoot;
import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
import static com.android.server.stats.Flags.applyNetworkStatsPollRateLimit;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
@@ -229,6 +230,7 @@
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
+import com.android.server.stats.pull.netstats.NetworkStatsAccumulator;
import com.android.server.stats.pull.netstats.NetworkStatsExt;
import com.android.server.stats.pull.netstats.SubInfo;
import com.android.server.storage.DiskStatsFileLogger;
@@ -424,6 +426,14 @@
@GuardedBy("mDataBytesTransferLock")
private final ArrayList<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
+ // Accumulates NetworkStats from initialization till the present moment.
+ // It is necessary to accumulate stats internally, because NetworkStats persists data for a
+ // limited amount of time, after which diff becomes incorrect without accumulation.
+ @NonNull
+ @GuardedBy("mDataBytesTransferLock")
+ private final ArrayList<NetworkStatsAccumulator> mNetworkStatsAccumulators =
+ new ArrayList<>();
+
@GuardedBy("mDataBytesTransferLock")
private long mLastNetworkStatsPollTime = -NETSTATS_POLL_RATE_LIMIT_MS;
@@ -1265,49 +1275,39 @@
case FrameworkStatsLog.WIFI_BYTES_TRANSFER: {
final NetworkStats stats = getUidNetworkStatsSnapshotForTransportLocked(
TRANSPORT_WIFI);
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
- new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
+ new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
break;
}
case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
final NetworkStats stats = getUidNetworkStatsSnapshotForTransportLocked(
TRANSPORT_WIFI);
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+ new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
break;
}
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: {
final NetworkStats stats =
getUidNetworkStatsSnapshotForTransportLocked(TRANSPORT_CELLULAR);
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
- new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
break;
}
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
final NetworkStats stats =
getUidNetworkStatsSnapshotForTransportLocked(TRANSPORT_CELLULAR);
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
break;
}
case FrameworkStatsLog.PROXY_BYTES_TRANSFER_BY_FG_BG: {
final NetworkStats stats = getUidNetworkStatsSnapshotForTemplateLocked(
new NetworkTemplate.Builder(MATCH_PROXY).build(), /*includeTags=*/false);
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[]{TRANSPORT_BLUETOOTH},
- /*slicedByFgbg=*/true, /*slicedByTag=*/false,
- /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/true));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+ new int[]{TRANSPORT_BLUETOOTH},
+ /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+ /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/true));
break;
}
case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: {
@@ -1316,14 +1316,12 @@
final NetworkStats cellularStats = getUidNetworkStatsSnapshotForTemplateLocked(
new NetworkTemplate.Builder(MATCH_MOBILE)
.setMeteredness(METERED_YES).build(), /*includeTags=*/true);
- if (wifiStats != null && cellularStats != null) {
- final NetworkStats stats = wifiStats.add(cellularStats);
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
- new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
- /*slicedByFgbg=*/false, /*slicedByTag=*/true,
- /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/false));
- }
+ final NetworkStats stats = wifiStats.add(cellularStats);
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
+ new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
+ /*slicedByFgbg=*/false, /*slicedByTag=*/true,
+ /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/false));
break;
}
case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER: {
@@ -1509,12 +1507,10 @@
final NetworkStats stats = getUidNetworkStatsSnapshotForTemplateLocked(
template, false);
final Integer transport = ruleAndTransport.second;
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
- /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- /*subInfo=*/null, oemManaged, /*isTypeProxy=*/false));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
+ new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+ /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ /*subInfo=*/null, oemManaged, /*isTypeProxy=*/false));
}
}
@@ -1525,7 +1521,7 @@
* Create a snapshot of NetworkStats for a given transport.
*/
@GuardedBy("mDataBytesTransferLock")
- @Nullable
+ @NonNull
private NetworkStats getUidNetworkStatsSnapshotForTransportLocked(int transport) {
NetworkTemplate template = null;
switch (transport) {
@@ -1564,20 +1560,49 @@
* some traffic before boot.
*/
@GuardedBy("mDataBytesTransferLock")
- @Nullable
+ @NonNull
private NetworkStats getUidNetworkStatsSnapshotForTemplateLocked(
@NonNull NetworkTemplate template, boolean includeTags) {
final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
- final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
- final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(),
+ final long currentTimeMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
+ final long bootTimeMillis = currentTimeMillis - elapsedMillisSinceBoot;
+ final long bucketDurationMillis = Settings.Global.getLong(mContext.getContentResolver(),
NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS);
- // Set startTime before boot so that NetworkStats includes at least one full bucket.
- // Set endTime in the future so that NetworkStats includes everything in the active bucket.
- final long startTime = currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration;
- final long endTime = currentTimeInMillis + bucketDuration;
+ if (accumulateNetworkStatsSinceBoot()) {
+ NetworkStatsAccumulator accumulator = CollectionUtils.find(
+ mNetworkStatsAccumulators, it -> it.hasEqualParameters(template, includeTags));
+ if (accumulator == null) {
+ accumulator = new NetworkStatsAccumulator(
+ template,
+ includeTags,
+ bucketDurationMillis,
+ bootTimeMillis - bucketDurationMillis);
+ mNetworkStatsAccumulators.add(accumulator);
+ }
- // NetworkStatsManager#forceUpdate updates stats for all networks
+ return accumulator.queryStats(currentTimeMillis,
+ (aTemplate, aIncludeTags, aStartTime, aEndTime) -> {
+ synchronized (mDataBytesTransferLock) {
+ return getUidNetworkStatsSnapshotForTemplateLocked(aTemplate,
+ aIncludeTags, aStartTime, aEndTime);
+ }
+ });
+
+ } else {
+ // Set end time in the future to include all stats in the active bucket.
+ return getUidNetworkStatsSnapshotForTemplateLocked(
+ template, includeTags,
+ bootTimeMillis - bucketDurationMillis,
+ currentTimeMillis + bucketDurationMillis);
+ }
+ }
+
+ @GuardedBy("mDataBytesTransferLock")
+ @NonNull
+ private NetworkStats getUidNetworkStatsSnapshotForTemplateLocked(
+ @NonNull NetworkTemplate template, boolean includeTags, long startTime, long endTime) {
+ final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
if (applyNetworkStatsPollRateLimit()) {
// The new way: rate-limit force-polling for all NetworkStats queries
if (elapsedMillisSinceBoot - mLastNetworkStatsPollTime >= NETSTATS_POLL_RATE_LIMIT_MS) {
@@ -1621,12 +1646,10 @@
.setMeteredness(METERED_YES).build();
final NetworkStats stats =
getUidNetworkStatsSnapshotForTemplateLocked(template, /*includeTags=*/false);
- if (stats != null) {
- ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
- new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
- /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
- OEM_MANAGED_ALL, /*isTypeProxy=*/false));
- }
+ ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
+ /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
+ OEM_MANAGED_ALL, /*isTypeProxy=*/false));
}
return ret;
}
diff --git a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
new file mode 100644
index 0000000..e798bc4
--- /dev/null
+++ b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsAccumulator.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 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.server.stats.pull.netstats;
+
+import android.annotation.NonNull;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+
+import java.util.Objects;
+
+/**
+ * A class that queries NetworkStats, accumulates query results, and exposes cumulative stats across
+ * the time range covered by the queries. This class is not thread-safe.
+ * <p>
+ * This is class should be used when querying NetworkStats since boot, as NetworkStats persists data
+ * only for a limited period of time.
+ *
+ * @hide
+ */
+public class NetworkStatsAccumulator {
+
+ private final NetworkTemplate mTemplate;
+ private final boolean mWithTags;
+ private final long mBucketDurationMillis;
+ private NetworkStats mSnapshot;
+ private long mSnapshotEndTimeMillis;
+
+ public NetworkStatsAccumulator(@NonNull NetworkTemplate template, boolean withTags,
+ long bucketDurationMillis, long snapshotEndTimeMillis) {
+ mTemplate = template;
+ mWithTags = withTags;
+ mBucketDurationMillis = bucketDurationMillis;
+ mSnapshot = new NetworkStats(0, 1);
+ mSnapshotEndTimeMillis = snapshotEndTimeMillis;
+ }
+
+ /**
+ * Provides cumulative NetworkStats until given timestamp.
+ * <p>
+ * This method method may call {@code queryFunction} more than once, which includes maintaining
+ * an internal cumulative stats snapshot and querying stats after the snapshot.
+ */
+ @NonNull
+ public NetworkStats queryStats(long currentTimeMillis,
+ @NonNull StatsQueryFunction queryFunction) {
+ maybeExpandSnapshot(currentTimeMillis, queryFunction);
+ return snapshotPlusFollowingStats(currentTimeMillis, queryFunction);
+ }
+
+ /**
+ * Returns true if the accumulator is using given query parameters.
+ */
+ public boolean hasEqualParameters(@NonNull NetworkTemplate template, boolean withTags) {
+ return Objects.equals(mTemplate, template) && mWithTags == withTags;
+ }
+
+ /**
+ * Expands the internal cumulative stats snapshot, if possible, by querying NetworkStats.
+ */
+ private void maybeExpandSnapshot(long currentTimeMillis,
+ @NonNull StatsQueryFunction queryFunction) {
+ // Update snapshot only if it is possible to expand it by at least one full bucket, and only
+ // if the new snapshot's end is not in the active bucket.
+ long newEndTimeMillis = currentTimeMillis - mBucketDurationMillis;
+ if (newEndTimeMillis - mSnapshotEndTimeMillis > mBucketDurationMillis) {
+ NetworkStats extraStats = queryFunction.queryNetworkStats(mTemplate, mWithTags,
+ mSnapshotEndTimeMillis, newEndTimeMillis);
+ mSnapshot = mSnapshot.add(extraStats);
+ mSnapshotEndTimeMillis = newEndTimeMillis;
+ }
+ }
+
+ /**
+ * Adds up stats in the internal cumulative snapshot and the stats that follow after it.
+ */
+ @NonNull
+ private NetworkStats snapshotPlusFollowingStats(long currentTimeMillis,
+ @NonNull StatsQueryFunction queryFunction) {
+ // Set end time in the future to include all stats in the active bucket.
+ NetworkStats extraStats = queryFunction.queryNetworkStats(mTemplate, mWithTags,
+ mSnapshotEndTimeMillis, currentTimeMillis + mBucketDurationMillis);
+ return mSnapshot.add(extraStats);
+ }
+
+ @FunctionalInterface
+ public interface StatsQueryFunction {
+ /**
+ * Returns network stats during the given time period.
+ */
+ @NonNull
+ NetworkStats queryNetworkStats(@NonNull NetworkTemplate template, boolean includeTags,
+ long startTime, long endTime);
+ }
+}
diff --git a/services/core/java/com/android/server/stats/stats_flags.aconfig b/services/core/java/com/android/server/stats/stats_flags.aconfig
index afea303..8686458f 100644
--- a/services/core/java/com/android/server/stats/stats_flags.aconfig
+++ b/services/core/java/com/android/server/stats/stats_flags.aconfig
@@ -30,3 +30,11 @@
bug: "352495181"
is_fixed_read_only: true
}
+
+flag {
+ name: "accumulate_network_stats_since_boot"
+ namespace: "statsd"
+ description: "Accumulate results of NetworkStats queries to avoid hitting NetworkStats persistence limit"
+ bug: "352537247"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 31f4d08..c7fafe9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3198,6 +3198,9 @@
if (!compatEnabled && !mWmService.mConstants.mIgnoreActivityOrientationRequest) {
return false;
}
+ if (mWmService.mConstants.isPackageOptOutIgnoreActivityOrientationRequest(packageName)) {
+ return false;
+ }
// If the user preference respects aspect ratio, then it becomes non-resizable.
return !mAppCompatController.getAppCompatOverrides().getAppCompatAspectRatioOverrides()
.shouldApplyUserMinAspectRatioOverride();
@@ -5877,6 +5880,7 @@
return;
}
+ final State prevState = mState;
mState = state;
if (getTaskFragment() != null) {
@@ -5917,6 +5921,14 @@
mAtmService.updateBatteryStats(this, false);
mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
break;
+ case STOPPING:
+ // It is possible that an Activity is scheduled to be STOPPED directly from RESUMED
+ // state. Updating the PAUSED usage state in that case, since the Activity will be
+ // STOPPED while cycled through the PAUSED state.
+ if (prevState == RESUMED) {
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
+ }
+ break;
case STOPPED:
mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
if (mDisplayContent != null) {
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
index 1d00136..8c5689c1 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.CameraCompatTaskInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.res.Configuration;
import android.widget.Toast;
@@ -250,6 +251,14 @@
cameraCompatFreeformPolicyAspectRatio);
}
+ @CameraCompatTaskInfo.FreeformCameraCompatMode
+ static int getCameraCompatFreeformMode(@NonNull ActivityRecord activity) {
+ final AppCompatCameraPolicy cameraPolicy = getAppCompatCameraPolicy(activity);
+ return cameraPolicy != null && cameraPolicy.mCameraCompatFreeformPolicy != null
+ ? cameraPolicy.mCameraCompatFreeformPolicy.getCameraCompatMode(activity)
+ : CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+ }
+
/**
* Whether we should apply the min aspect ratio per-app override only when an app is connected
* to the camera.
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
index 69421d0..8d84248 100644
--- a/services/core/java/com/android/server/wm/AppCompatUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -185,8 +185,8 @@
&& aspectRatioOverrides.shouldEnableUserAspectRatioSettings();
appCompatTaskInfo.setEligibleForUserAspectRatioButton(eligibleForAspectRatioButton);
appCompatTaskInfo.setTopActivityLetterboxed(top.areBoundsLetterboxed());
- appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = top.mAppCompatController
- .getAppCompatCameraOverrides().getFreeformCameraCompatMode();
+ appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode =
+ AppCompatCameraPolicy.getCameraCompatFreeformMode(top);
appCompatTaskInfo.setHasMinAspectRatioOverride(top.mAppCompatController
.getDesktopAppCompatAspectRatioPolicy().hasMinAspectRatioOverride(task));
}
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 4f0cbf9..2a0252a 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -21,6 +21,8 @@
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_DISPLAY_ROTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -35,6 +37,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.CameraCompatTaskInfo;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.view.DisplayInfo;
@@ -64,8 +67,6 @@
@NonNull
private final CameraStateMonitor mCameraStateMonitor;
- private boolean mIsCameraCompatTreatmentPending = false;
-
@Nullable
private Task mCameraTask;
@@ -100,13 +101,27 @@
return mIsRunning;
}
- // Refreshing only when configuration changes after rotation or camera split screen aspect ratio
- // treatment is enabled.
+ // Refreshing only when configuration changes after applying camera compat treatment.
@Override
public boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
@NonNull Configuration newConfig,
@NonNull Configuration lastReportedConfig) {
- return isTreatmentEnabledForActivity(activity) && mIsCameraCompatTreatmentPending;
+ return isTreatmentEnabledForActivity(activity, /* shouldCheckOrientation= */ true)
+ && haveCameraCompatAttributesChanged(newConfig, lastReportedConfig);
+ }
+
+ private boolean haveCameraCompatAttributesChanged(@NonNull Configuration newConfig,
+ @NonNull Configuration lastReportedConfig) {
+ // Camera compat treatment changes the following:
+ // - Letterboxes app bounds to camera compat aspect ratio in app's requested orientation,
+ // - Changes display rotation so it matches what the app expects in its chosen orientation,
+ // - Rotate-and-crop camera feed to match that orientation (this changes iff the display
+ // rotation changes, so no need to check).
+ final long diff = newConfig.windowConfiguration.diff(lastReportedConfig.windowConfiguration,
+ /* compareUndefined= */ true);
+ final boolean appBoundsChanged = (diff & WINDOW_CONFIG_APP_BOUNDS) != 0;
+ final boolean displayRotationChanged = (diff & WINDOW_CONFIG_DISPLAY_ROTATION) != 0;
+ return appBoundsChanged || displayRotationChanged;
}
/**
@@ -132,22 +147,26 @@
@Override
public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
@NonNull String cameraId) {
- if (!isTreatmentEnabledForActivity(cameraActivity)) {
+ // Do not check orientation outside of the config recompute, as the app's orientation intent
+ // might be obscured by a fullscreen override. Especially for apps which have a camera
+ // functionality which is not the main focus of the app: while most of the app might work
+ // well in fullscreen, often the camera setup still assumes it will run on a portrait device
+ // in its natural orientation and comes out stretched or sideways.
+ // Config recalculation will later check the original orientation to avoid applying
+ // treatment to apps optimized for large screens.
+ if (!isTreatmentEnabledForActivity(cameraActivity, /* shouldCheckOrientation= */ false)) {
return;
}
- final int existingCameraCompatMode = cameraActivity.mAppCompatController
- .getAppCompatCameraOverrides()
- .getFreeformCameraCompatMode();
- final int newCameraCompatMode = getCameraCompatMode(cameraActivity);
- if (newCameraCompatMode != existingCameraCompatMode) {
- mIsCameraCompatTreatmentPending = true;
- mCameraTask = cameraActivity.getTask();
- cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
- .setFreeformCameraCompatMode(newCameraCompatMode);
- forceUpdateActivityAndTask(cameraActivity);
- } else {
- mIsCameraCompatTreatmentPending = false;
- }
+
+ cameraActivity.recomputeConfiguration();
+ updateCameraCompatMode(cameraActivity);
+ cameraActivity.getTask().dispatchTaskInfoChangedIfNeeded(/* force= */ true);
+ cameraActivity.ensureActivityConfiguration(/* ignoreVisibility= */ false);
+ }
+
+ private void updateCameraCompatMode(@NonNull ActivityRecord cameraActivity) {
+ cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .setFreeformCameraCompatMode(getCameraCompatMode(cameraActivity));
}
@Override
@@ -167,7 +186,6 @@
}
}
mCameraTask = null;
- mIsCameraCompatTreatmentPending = false;
return true;
}
@@ -184,13 +202,12 @@
// Camera compat should direct aspect ratio when in camera compat mode, unless an app has a
// different camera compat aspect ratio set: this allows per-app camera compat override
// aspect ratio to be smaller than the default.
- return isInCameraCompatMode(activity) && !activity.mAppCompatController
+ return isInFreeformCameraCompatMode(activity) && !activity.mAppCompatController
.getAppCompatCameraOverrides().isOverrideMinAspectRatioForCameraEnabled();
}
- private boolean isInCameraCompatMode(@NonNull ActivityRecord activity) {
- return activity.mAppCompatController.getAppCompatCameraOverrides()
- .getFreeformCameraCompatMode() != CAMERA_COMPAT_FREEFORM_NONE;
+ boolean isInFreeformCameraCompatMode(@NonNull ActivityRecord activity) {
+ return getCameraCompatMode(activity) != CAMERA_COMPAT_FREEFORM_NONE;
}
float getCameraCompatAspectRatio(@NonNull ActivityRecord activityRecord) {
@@ -201,16 +218,11 @@
return MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
}
- private void forceUpdateActivityAndTask(ActivityRecord cameraActivity) {
- cameraActivity.recomputeConfiguration();
- cameraActivity.updateReportedConfigurationAndSend();
- Task cameraTask = cameraActivity.getTask();
- if (cameraTask != null) {
- cameraTask.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
+ @CameraCompatTaskInfo.FreeformCameraCompatMode
+ int getCameraCompatMode(@NonNull ActivityRecord topActivity) {
+ if (!isTreatmentEnabledForActivity(topActivity, /* shouldCheckOrientation= */ true)) {
+ return CAMERA_COMPAT_FREEFORM_NONE;
}
- }
-
- private static int getCameraCompatMode(@NonNull ActivityRecord topActivity) {
final int appOrientation = topActivity.getRequestedConfigurationOrientation();
// It is very important to check the original (actual) display rotation, and not the
// sandboxed rotation that camera compat treatment sets.
@@ -250,15 +262,24 @@
* <ul>
* <li>Treatment is enabled.
* <li>Camera is active for the package.
- * <li>The app has a fixed orientation.
+ * <li>The app has a fixed orientation if {@code checkOrientation} is true.
* <li>The app is in freeform windowing mode.
* </ul>
+ *
+ * @param checkOrientation Whether to take apps orientation into account for this check. Only
+ * fixed-orientation apps should be targeted, but this might be
+ * obscured by OEMs via fullscreen override and the app's original
+ * intent inaccessible when the camera opens. Thus, policy would pass
+ * {@code false} here when considering whether to trigger config
+ * recalculation, and later pass {@code true} during recalculation.
*/
- private boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity) {
+ @VisibleForTesting
+ boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity,
+ boolean checkOrientation) {
int orientation = activity.getRequestedConfigurationOrientation();
return isCameraCompatForFreeformEnabledForActivity(activity)
&& mCameraStateMonitor.isCameraRunningForActivity(activity)
- && orientation != ORIENTATION_UNDEFINED
+ && (!checkOrientation || orientation != ORIENTATION_UNDEFINED)
&& activity.inFreeformWindowingMode()
// "locked" and "nosensor" values are often used by camera apps that can't
// handle dynamic changes so we shouldn't force-letterbox them.
@@ -270,7 +291,7 @@
private boolean isActivityForCameraIdRefreshing(@NonNull ActivityRecord topActivity,
@NonNull String cameraId) {
- if (!isTreatmentEnabledForActivity(topActivity)
+ if (!isTreatmentEnabledForActivity(topActivity, /* checkOrientation= */ true)
|| mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index 1a8f5fc..fcf88d3 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -36,7 +36,7 @@
import android.os.SystemProperties;
import android.util.Size;
import android.view.Gravity;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
import java.util.function.Consumer;
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index b5ea0bd..6bf1c46 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;
-import android.window.flags.DesktopModeFlags;
+import android.window.DesktopModeFlags;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index dcf0319..a4fe064 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
@@ -28,9 +29,12 @@
import android.gui.StalledTransactionInfo;
import android.os.Debug;
import android.os.IBinder;
+import android.os.Trace;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.view.Display;
import android.view.InputApplicationHandle;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -64,6 +68,12 @@
// which point the ActivityManager will enable dispatching.
private boolean mInputDispatchEnabled;
+ /**
+ * The last input devices info which may affect display configuration. This is a quick lookup
+ * to detect interested changes without entering WM lock.
+ */
+ private SparseIntArray mLastInputConfigurationSources;
+
public InputManagerCallback(WindowManagerService service) {
mService = service;
}
@@ -117,8 +127,16 @@
/** Notifies that the input device configuration has changed. */
@Override
public void notifyConfigurationChanged() {
- synchronized (mService.mGlobalLock) {
- mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "notifyConfigurationChanged");
+ final boolean changed = !com.android.window.flags.Flags.filterIrrelevantInputDeviceChange()
+ || updateLastInputConfigurationSources();
+
+ if (changed) {
+ synchronized (mService.mGlobalLock) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "inputDeviceConfigChanged");
+ mService.mRoot.forAllDisplays(DisplayContent::sendNewConfiguration);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
}
synchronized (mInputDevicesReadyMonitor) {
@@ -127,6 +145,40 @@
mInputDevicesReadyMonitor.notifyAll();
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+
+ /** Returns {@code true} if the change of input devices may affect display configuration. */
+ private boolean updateLastInputConfigurationSources() {
+ final InputDevice[] devices = mService.mInputManager.getInputDevices();
+ final SparseIntArray newSources = new SparseIntArray(8);
+ final SparseIntArray lastSources = mLastInputConfigurationSources;
+ boolean changed = lastSources == null;
+ for (InputDevice device : devices) {
+ final String descriptor = device.getDescriptor();
+ if (descriptor == null || device.isVirtual()) {
+ continue;
+ }
+ final int key = descriptor.hashCode();
+ // The interested attributes from DisplayContent#computeScreenConfiguration.
+ int newSourceHash = device.getSources();
+ newSourceHash = newSourceHash * 31 + device.getKeyboardType();
+ newSourceHash = newSourceHash * 31 + device.getAssociatedDisplayId();
+ newSourceHash = newSourceHash * 31 + (device.isExternal() ? 1 : 0);
+ newSourceHash = newSourceHash * 31 + (device.isEnabled() ? 1 : 0);
+ newSources.put(key, newSourceHash);
+ if (lastSources != null && !changed) {
+ final int lastSource = lastSources.get(key, 0 /* valueIfKeyNotFound */);
+ if (lastSource != newSourceHash) {
+ changed = true;
+ }
+ }
+ }
+ if (lastSources != null && lastSources.size() != newSources.size()) {
+ changed = true;
+ }
+ mLastInputConfigurationSources = newSources;
+ return changed;
}
/** Notifies that the pointer location configuration has changed. */
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 0c489d6..2fde5aa 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -62,6 +62,7 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.window.flags.Flags;
import java.io.PrintWriter;
@@ -73,6 +74,9 @@
*/
class KeyguardController {
+ private static final boolean ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS =
+ Flags.ensureKeyguardDoesTransitionStarting();
+
private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_ATM;
static final String KEYGUARD_SLEEP_TOKEN_TAG = "keyguard";
@@ -201,6 +205,19 @@
setWakeTransitionReady();
return;
}
+
+ if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+ final TransitionController transitionController =
+ mWindowManager.mAtmService.getTransitionController();
+ final Transition transition = transitionController.getCollectingTransition();
+ if (transition != null && displayId == DEFAULT_DISPLAY) {
+ if (!keyguardShowing && state.mKeyguardShowing) {
+ transition.addFlag(TRANSIT_FLAG_KEYGUARD_GOING_AWAY);
+ } else if (keyguardShowing && !state.mKeyguardShowing) {
+ transition.addFlag(TRANSIT_FLAG_KEYGUARD_APPEARING);
+ }
+ }
+ }
// Update the task snapshot if the screen will not be turned off. To make sure that the
// unlocking animation can animate consistent content. The conditions are:
// - Either AOD or keyguard changes to be showing. So if the states change individually,
@@ -231,8 +248,10 @@
|| (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))) {
// Keyguard decided to show or stopped going away. Send a transition to animate back
// to the locked state before holding the sleep token again
- dc.requestTransitionAndLegacyPrepare(
- TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING);
+ if (!ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
+ dc.requestTransitionAndLegacyPrepare(
+ TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING);
+ }
dc.mWallpaperController.adjustWallpaperWindows();
dc.executeAppTransition();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index af57c84..95cf6bc 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -36,7 +36,7 @@
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
-import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS;
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index e0f24d8..31ca24c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -22,10 +22,12 @@
import android.provider.AndroidDeviceConfig;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -38,6 +40,10 @@
private static final String KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST =
"ignore_activity_orientation_request";
+ /** The packages that ignore {@link #KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST}. */
+ private static final String KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST =
+ "opt_out_ignore_activity_orientation_request_list";
+
/**
* The minimum duration between gesture exclusion logging for a given window in
* milliseconds.
@@ -65,6 +71,9 @@
/** @see #KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST */
boolean mIgnoreActivityOrientationRequest;
+ /** @see #KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST */
+ private ArraySet<String> mOptOutIgnoreActivityOrientationRequestPackages;
+
private final WindowManagerGlobalLock mGlobalLock;
private final Runnable mUpdateSystemGestureExclusionCallback;
private final DeviceConfigInterface mDeviceConfig;
@@ -97,6 +106,7 @@
updateSystemGestureExclusionLimitDp();
updateSystemGestureExcludedByPreQStickyImmersive();
updateIgnoreActivityOrientationRequest();
+ updateOptOutIgnoreActivityOrientationRequestList();
}
private void onAndroidPropertiesChanged(DeviceConfig.Properties properties) {
@@ -138,6 +148,9 @@
case KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST:
updateIgnoreActivityOrientationRequest();
break;
+ case KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST:
+ updateOptOutIgnoreActivityOrientationRequestList();
+ break;
default:
break;
}
@@ -169,6 +182,25 @@
KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST, false);
}
+ private void updateOptOutIgnoreActivityOrientationRequestList() {
+ final String packageList = mDeviceConfig.getString(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST, "");
+ if (packageList.isEmpty()) {
+ mOptOutIgnoreActivityOrientationRequestPackages = null;
+ return;
+ }
+ mOptOutIgnoreActivityOrientationRequestPackages = new ArraySet<>();
+ mOptOutIgnoreActivityOrientationRequestPackages.addAll(
+ Arrays.asList(packageList.split(",")));
+ }
+
+ boolean isPackageOptOutIgnoreActivityOrientationRequest(String packageName) {
+ return mIgnoreActivityOrientationRequest
+ && mOptOutIgnoreActivityOrientationRequestPackages != null
+ && mOptOutIgnoreActivityOrientationRequestPackages.contains(packageName);
+ }
+
void dump(PrintWriter pw) {
pw.println("WINDOW MANAGER CONSTANTS (dumpsys window constants):");
@@ -180,6 +212,10 @@
pw.print("="); pw.println(mSystemGestureExcludedByPreQStickyImmersive);
pw.print(" "); pw.print(KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST);
pw.print("="); pw.println(mIgnoreActivityOrientationRequest);
+ if (mOptOutIgnoreActivityOrientationRequestPackages != null) {
+ pw.print(" "); pw.print(KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST);
+ pw.print("="); pw.println(mOptOutIgnoreActivityOrientationRequestPackages);
+ }
pw.println();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index f8d0bc2..2229807 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -51,6 +51,7 @@
import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT;
import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN;
import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
@@ -121,6 +122,7 @@
import android.window.ITransitionPlayer;
import android.window.IWindowContainerTransactionCallback;
import android.window.IWindowOrganizerController;
+import android.window.KeyguardState;
import android.window.RemoteTransition;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentCreationParams;
@@ -1253,6 +1255,10 @@
caller, errorCallbackToken, organizer);
break;
}
+ case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE: {
+ effects |= applyKeyguardState(hop);
+ break;
+ }
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
final Bundle launchOpts = hop.getLaunchOptions();
ActivityOptions activityOptions = launchOpts != null
@@ -1788,6 +1794,19 @@
return effects;
}
+ private int applyKeyguardState(@NonNull WindowContainerTransaction.HierarchyOp hop) {
+ int effects = TRANSACT_EFFECTS_NONE;
+
+ final KeyguardState keyguardState = hop.getKeyguardState();
+ if (keyguardState != null) {
+ int displayId = keyguardState.getDisplayId();
+ boolean keyguardShowing = keyguardState.getKeyguardShowing();
+ boolean aodShowing = keyguardState.getAodShowing();
+ mService.mKeyguardController.setKeyguardShown(displayId, keyguardShowing, aodShowing);
+ }
+ return effects;
+ }
+
/**
* Executes the provided {@code runnable} after the {@code transition}. If the
* {@code transition} is {@code null}, the {@code runnable} is executed immediately.
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 6093a67..1a1c8e5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -50,6 +50,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
@@ -3445,6 +3446,31 @@
verify(dpc).onDisplayChanged(/* hbmMetadata= */ null, Layout.NO_LEAD_DISPLAY);
}
+ @Test
+ public void testCreateAndReleaseVirtualDisplay_CalledWithTheSameUid() {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ registerDefaultDisplays(displayManager);
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ VirtualDisplayConfig config = mock(VirtualDisplayConfig.class);
+ Surface surface = mock(Surface.class);
+ when(config.getSurface()).thenReturn(surface);
+ int callingUid = Binder.getCallingUid();
+ IBinder binder = mock(IBinder.class);
+ when(mMockAppToken.asBinder()).thenReturn(binder);
+ String uniqueId = "123";
+ when(config.getUniqueId()).thenReturn(uniqueId);
+
+ bs.createVirtualDisplay(config, mMockAppToken, /* projection= */ null, PACKAGE_NAME);
+ verify(mMockVirtualDisplayAdapter).createVirtualDisplayLocked(eq(mMockAppToken),
+ /* projection= */ isNull(), eq(callingUid), eq(PACKAGE_NAME),
+ eq("virtual:" + PACKAGE_NAME + ":" + uniqueId), eq(surface), /* flags= */ anyInt(),
+ eq(config));
+
+ bs.releaseVirtualDisplay(mMockAppToken);
+ verify(mMockVirtualDisplayAdapter).releaseVirtualDisplayLocked(binder, callingUid);
+ }
+
private void initDisplayPowerController(DisplayManagerInternal localService) {
localService.initPowerManagement(new DisplayManagerInternal.DisplayPowerCallbacks() {
@Override
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index 81e6cc3..3ac7fb0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -21,71 +21,104 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
-import android.content.Context;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
+import android.media.projection.IMediaProjection;
import android.os.IBinder;
import android.os.Process;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.testing.TestableContext;
+import android.view.Surface;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.R;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.testutils.TestHandler;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class VirtualDisplayAdapterTest {
- @Mock
- Context mContextMock;
+ private static final int MAX_DEVICES = 3;
+ private static final int MAX_DEVICES_PER_PACKAGE = 2;
+
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
@Mock
- VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
+ private VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
@Mock
- DisplayAdapter.Listener mMockListener;
+ private DisplayAdapter.Listener mMockListener;
@Mock
- IVirtualDisplayCallback mMockCallback;
+ private IVirtualDisplayCallback mMockCallback;
@Mock
- IBinder mMockBinder;
+ private IBinder mMockBinder;
+
+ @Mock
+ private IMediaProjection mMediaProjectionMock;
+
+ @Mock
+ private Surface mSurfaceMock;
+
+ @Mock
+ private VirtualDisplayConfig mVirtualDisplayConfigMock;
private TestHandler mHandler;
- private VirtualDisplayAdapter mVirtualDisplayAdapter;
-
@Mock
private DisplayManagerFlags mFeatureFlags;
+ private VirtualDisplayAdapter mAdapter;
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ mContext.getOrCreateTestableResources().addOverride(R.integer.config_virtualDisplayLimit,
+ MAX_DEVICES);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.integer.config_virtualDisplayLimitPerPackage, MAX_DEVICES_PER_PACKAGE);
+
mHandler = new TestHandler(null);
- mVirtualDisplayAdapter = new VirtualDisplayAdapter(new DisplayManagerService.SyncRoot(),
- mContextMock, mHandler, mMockListener, mMockSufaceControlDisplayFactory,
- mFeatureFlags);
+ mAdapter = new VirtualDisplayAdapter(new DisplayManagerService.SyncRoot(), mContext,
+ mHandler, mMockListener, mMockSufaceControlDisplayFactory, mFeatureFlags);
when(mMockCallback.asBinder()).thenReturn(mMockBinder);
}
@Test
- public void testCreatesVirtualDisplay() {
+ public void testCreateAndReleaseVirtualDisplay() {
VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("test", /* width= */ 1,
/* height= */ 1, /* densityDpi= */ 1).build();
+ int ownerUid = 10;
- DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback,
- /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+ DisplayDevice result = mAdapter.createVirtualDisplayLocked(mMockCallback,
+ /* projection= */ null, ownerUid, /* packageName= */ "testpackage",
/* uniqueId= */ "uniqueId", /* surface= */ null, /* flags= */ 0, config);
+ assertNotNull(result);
+ result = mAdapter.releaseVirtualDisplayLocked(mMockBinder, ownerUid);
assertNotNull(result);
}
@@ -98,7 +131,7 @@
final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
packageName, Process.myUid(), config);
- DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+ DisplayDevice result = mAdapter.createVirtualDisplayLocked(
mMockCallback, /* projection= */ null, /* ownerUid= */ 10,
packageName, displayUniqueId, /* surface= */ null, /* flags= */ 0, config);
@@ -114,14 +147,194 @@
/* height= */ 1, /* densityDpi= */ 1).build();
VirtualDisplayConfig config2 = new VirtualDisplayConfig.Builder("test2", /* width= */ 1,
/* height= */ 1, /* densityDpi= */ 1).build();
- mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback, /* projection= */ null,
- /* ownerUid= */ 10, /* packageName= */ "testpackage", /* uniqueId= */ "uniqueId1",
- /* surface= */ null, /* flags= */ 0, config1);
- DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback,
+ DisplayDevice result = mAdapter.createVirtualDisplayLocked(mMockCallback,
+ /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+ /* uniqueId= */ "uniqueId1", /* surface= */ null, /* flags= */ 0, config1);
+ assertNotNull(result);
+
+ result = mAdapter.createVirtualDisplayLocked(mMockCallback,
/* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
/* uniqueId= */ "uniqueId2", /* surface= */ null, /* flags= */ 0, config2);
-
assertNull(result);
}
+
+ @Test
+ public void testCreateManyVirtualDisplays_LimitFlagDisabled() {
+ when(mFeatureFlags.isVirtualDisplayLimitEnabled()).thenReturn(false);
+
+ // Displays for the same package
+ for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) {
+ // Same owner UID
+ IVirtualDisplayCallback callback = createCallback();
+ DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+ mMediaProjectionMock, 1234, "test.package", "123",
+ mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+ assertNotNull(device);
+ }
+
+ // Displays for different packages
+ for (int i = 0; i < MAX_DEVICES * 2; i++) {
+ // Same owner UID
+ IVirtualDisplayCallback callback = createCallback();
+ DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+ mMediaProjectionMock, 1234 + i, "test.package", "123",
+ mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+ assertNotNull(device);
+ }
+ }
+
+ @Test
+ public void testCreateVirtualDisplay_MaxDisplaysPerPackage() {
+ when(mFeatureFlags.isVirtualDisplayLimitEnabled()).thenReturn(true);
+ List<IVirtualDisplayCallback> callbacks = new ArrayList<>();
+ int ownerUid = 1234;
+
+ for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) {
+ // Same owner UID
+ IVirtualDisplayCallback callback = createCallback();
+ DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+ mMediaProjectionMock, ownerUid, "test.package", "123",
+ mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+ if (i < MAX_DEVICES_PER_PACKAGE) {
+ assertNotNull(device);
+ callbacks.add(callback);
+ } else {
+ assertNull(device);
+ }
+ }
+
+ // Release one display
+ DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder(),
+ ownerUid);
+ assertNotNull(device);
+ callbacks.remove(0);
+
+ // We should be able to create another display
+ IVirtualDisplayCallback callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid,
+ "test.package", "123", mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+ assertNotNull(device);
+ callbacks.add(callback);
+
+ // But only one
+ callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid,
+ "test.package", "123", mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+ assertNull(device);
+
+ // Release all the displays
+ for (IVirtualDisplayCallback cb : callbacks) {
+ device = mAdapter.releaseVirtualDisplayLocked(cb.asBinder(), ownerUid);
+ assertNotNull(device);
+ }
+ callbacks.clear();
+
+ // We should be able to create the max number of displays again
+ for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) {
+ // Same owner UID
+ callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid,
+ "test.package", "123", mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+ if (i < MAX_DEVICES_PER_PACKAGE) {
+ assertNotNull(device);
+ callbacks.add(callback);
+ } else {
+ assertNull(device);
+ }
+ }
+
+ // We should be able to create a display for a different package
+ callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, ownerUid + 1,
+ "test.package", "123", mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+ assertNotNull(device);
+ callbacks.add(callback);
+ }
+
+ @Test
+ public void testCreateVirtualDisplay_MaxDisplays() {
+ when(mFeatureFlags.isVirtualDisplayLimitEnabled()).thenReturn(true);
+ List<IVirtualDisplayCallback> callbacks = new ArrayList<>();
+ int firstOwnerUid = 1000;
+
+ for (int i = 0; i < MAX_DEVICES * 2; i++) {
+ // Different owner UID
+ IVirtualDisplayCallback callback = createCallback();
+ DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback,
+ mMediaProjectionMock, firstOwnerUid + i, "test.package",
+ "123", mSurfaceMock, /* flags= */ 0, mVirtualDisplayConfigMock);
+ if (i < MAX_DEVICES) {
+ assertNotNull(device);
+ callbacks.add(callback);
+ } else {
+ assertNull(device);
+ }
+ }
+
+ // Release one display
+ DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder(),
+ firstOwnerUid);
+ assertNotNull(device);
+ callbacks.remove(0);
+
+ // We should be able to create another display
+ IVirtualDisplayCallback callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock,
+ firstOwnerUid, "test.package", "123", mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+ assertNotNull(device);
+ callbacks.add(callback);
+
+ // But only one
+ callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock,
+ firstOwnerUid, "test.package", "123", mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+ assertNull(device);
+
+ // Release all the displays
+ for (int i = 0; i < callbacks.size(); i++) {
+ device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(i).asBinder(),
+ firstOwnerUid + i);
+ assertNotNull(device);
+ }
+ callbacks.clear();
+
+ // We should be able to create the max number of displays again
+ for (int i = 0; i < MAX_DEVICES * 2; i++) {
+ // Different owner UID
+ callback = createCallback();
+ device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock,
+ firstOwnerUid + i, "test.package", "123", mSurfaceMock,
+ /* flags= */ 0, mVirtualDisplayConfigMock);
+ if (i < MAX_DEVICES) {
+ assertNotNull(device);
+ callbacks.add(callback);
+ } else {
+ assertNull(device);
+ }
+ }
+ }
+
+ private IVirtualDisplayCallback createCallback() {
+ return new IVirtualDisplayCallback.Stub() {
+
+ @Override
+ public void onPaused() {
+ }
+
+ @Override
+ public void onResumed() {
+ }
+
+ @Override
+ public void onStopped() {
+ }
+ };
+ }
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index d91f154..58f0ab4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -1872,6 +1872,60 @@
}
@Test
+ public void testPeakRefreshRate_notAppliedToExternalDisplays() {
+ when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+ .thenReturn(true);
+ mInjector.mDisplayInfo.type = Display.TYPE_EXTERNAL;
+ DisplayModeDirector director =
+ new DisplayModeDirector(mContext, mHandler, mInjector,
+ mDisplayManagerFlags, mDisplayDeviceConfigProvider);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+ director.getDisplayObserver().onDisplayAdded(DISPLAY_ID);
+ director.getDisplayObserver().onDisplayAdded(DISPLAY_ID_2);
+
+ Display.Mode[] modes1 = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 130),
+ };
+ Display.Mode[] modes2 = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 140),
+ };
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
+ supportedModesByDisplay.put(DISPLAY_ID, modes1);
+ supportedModesByDisplay.put(DISPLAY_ID_2, modes2);
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+ director.injectSupportedModesByDisplay(supportedModesByDisplay);
+
+ // Disable Smooth Display
+ setPeakRefreshRate(RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);
+
+ Vote vote1 = director.getVote(DISPLAY_ID,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ Vote vote2 = director.getVote(DISPLAY_ID_2,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertThat(vote1).isNull();
+ assertThat(vote2).isNull();
+
+ // Enable Smooth Display
+ setPeakRefreshRate(Float.POSITIVE_INFINITY);
+
+ vote1 = director.getVote(DISPLAY_ID,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ vote2 = director.getVote(DISPLAY_ID_2,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertThat(vote1).isNull();
+ assertThat(vote2).isNull();
+ }
+
+ @Test
public void testPeakRefreshRate_DisplayChanged() {
when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
.thenReturn(true);
@@ -1968,8 +2022,9 @@
@Test
@Parameters({
"true, true, 60",
- "false, true, 50",
- "true, false, 50"
+ "false, true, 60",
+ "true, false, 50",
+ "false, false, 50"
})
public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled,
boolean isExternalDisplay, float expectedMaxRenderFrameRate) {
@@ -3810,6 +3865,7 @@
SensorManagerInternal sensorManagerInternal) {
mDeviceConfig = new FakeDeviceConfig();
mDisplayInfo = new DisplayInfo();
+ mDisplayInfo.type = Display.TYPE_INTERNAL;
mDisplayInfo.defaultModeId = MODE_ID;
mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
800, 600, /* refreshRate= */ 60)};
@@ -3856,6 +3912,7 @@
@Override
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
displayInfo.copyFrom(mDisplayInfo);
+ displayInfo.displayId = displayId;
return mDisplayInfoValid;
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
index 5e240cf..e3f150e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
@@ -189,6 +189,7 @@
@Test
public void testExternalDisplay_voteUserPreferredMode() {
when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()).thenReturn(false);
var preferredMode = mExternalDisplayModes[5];
mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
var expectedVote = Vote.forSize(
@@ -229,6 +230,108 @@
.isEqualTo(null);
}
+ /** Vote for user preferred mode */
+ @Test
+ public void testDefaultDisplay_voteUserPreferredMode() {
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()).thenReturn(true);
+ var preferredMode = mInternalDisplayModes[5];
+ mInternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ var expectedVote = Vote.forSize(
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight());
+ init();
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ mObserver.onDisplayAdded(DEFAULT_DISPLAY);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+
+ mInternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ mObserver.onDisplayChanged(DEFAULT_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ preferredMode = mInternalDisplayModes[4];
+ mInternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ expectedVote = Vote.forSize(
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight());
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ mObserver.onDisplayChanged(DEFAULT_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ // Testing that the vote is removed.
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ }
+
+ /** Vote for user preferred mode with refresh rate, synchronization vote must be disabled */
+ @Test
+ public void testExternalDisplay_voteUserPreferredMode_withRefreshRate() {
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isDisplaysRefreshRatesSynchronizationEnabled()).thenReturn(false);
+ when(mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()).thenReturn(true);
+ var preferredMode = mExternalDisplayModes[5];
+ mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ var expectedVote = Vote.forSizeAndPhysicalRefreshRatesRange(
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight(),
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight(),
+ preferredMode.getRefreshRate(),
+ preferredMode.getRefreshRate());
+ init();
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+
+ mExternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ preferredMode = mExternalDisplayModes[4];
+ mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ expectedVote = Vote.forSizeAndPhysicalRefreshRatesRange(
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight(),
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight(),
+ preferredMode.getRefreshRate(),
+ preferredMode.getRefreshRate());
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+
+ // Testing that the vote is removed.
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ }
+
/** External display: Do not apply limit to user preferred mode */
@Test
public void testExternalDisplay_doNotApplyLimitToUserPreferredMode() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 2107406..412599d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -171,6 +171,8 @@
private static int sUiTierSize = 5;
private Context mContext;
+ private ProcessStateController mProcessStateController;
+ private ActiveUids mActiveUids;
private PackageManagerInternal mPackageManagerInternal;
private ActivityManagerService mService;
private OomAdjusterInjector mInjector = new OomAdjusterInjector();
@@ -229,15 +231,19 @@
doCallRealMethod().when(mService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
doCallRealMethod().when(mService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
+
doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
anyInt());
doNothing().when(pr).enqueueProcessChangeItemLocked(anyInt(), anyInt(), anyInt(),
anyBoolean());
- mService.mOomAdjuster = mService.mConstants.ENABLE_NEW_OOMADJ
- ? new OomAdjusterModernImpl(mService, mService.mProcessList,
- new ActiveUids(mService, false), mInjector)
- : new OomAdjuster(mService, mService.mProcessList, new ActiveUids(mService, false),
- mInjector);
+ mActiveUids = new ActiveUids(mService, false);
+ mProcessStateController = new ProcessStateController.Builder(mService,
+ mService.mProcessList, mActiveUids)
+ .useModernOomAdjuster(mService.mConstants.ENABLE_NEW_OOMADJ)
+ .setOomAdjusterInjector(mInjector)
+ .build();
+ mService.mProcessStateController = mProcessStateController;
+ mService.mOomAdjuster = mService.mProcessStateController.getOomAdjuster();
mService.mOomAdjuster.mAdjSeq = 10000;
mService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
mSetFlagsRule.enableFlags(Flags.FLAG_NEW_FGS_RESTRICTION_LOGIC);
@@ -246,8 +252,8 @@
@SuppressWarnings("GuardedBy")
@After
public void tearDown() {
- mService.mOomAdjuster.resetInternal();
- mService.mOomAdjuster.mActiveUids.clear();
+ mProcessStateController.getOomAdjuster().resetInternal();
+ mActiveUids.clear();
LocalServices.removeServiceForTest(PackageManagerInternal.class);
mInjector.reset();
}
@@ -293,7 +299,7 @@
private void updateOomAdj(ProcessRecord... apps) {
if (apps.length == 0) {
updateProcessRecordNodes(mService.mProcessList.getLruProcessesLOSP());
- mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
} else {
updateProcessRecordNodes(Arrays.asList(apps));
if (apps.length == 1) {
@@ -301,10 +307,10 @@
if (!mService.mProcessList.getLruProcessesLOSP().contains(app)) {
mService.mProcessList.getLruProcessesLOSP().add(app);
}
- mService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
+ mProcessStateController.runUpdate(apps[0], OOM_ADJ_REASON_NONE);
} else {
setProcessesToLru(apps);
- mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
mService.mProcessList.getLruProcessesLOSP().clear();
}
}
@@ -318,9 +324,9 @@
private void updateOomAdjPending(ProcessRecord... apps) {
setProcessesToLru(apps);
for (ProcessRecord app : apps) {
- mService.mOomAdjuster.enqueueOomAdjTargetLocked(app);
+ mProcessStateController.enqueueUpdateTarget(app);
}
- mService.mOomAdjuster.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_NONE);
+ mProcessStateController.runPendingUpdate(OOM_ADJ_REASON_NONE);
mService.mProcessList.getLruProcessesLOSP().clear();
}
@@ -341,11 +347,10 @@
public void testUpdateOomAdj_DoOne_Persistent_TopUi_Sleeping() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- app.mState.setHasTopUi(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ mProcessStateController.setMaxAdj(app, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setHasTopUi(app, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(app);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERSISTENT_PROC_ADJ,
SCHED_GROUP_RESTRICTED);
@@ -357,9 +362,9 @@
public void testUpdateOomAdj_DoOne_Persistent_TopUi_Awake() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- app.mState.setHasTopUi(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(app, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setHasTopUi(app, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
@@ -371,9 +376,9 @@
public void testUpdateOomAdj_DoOne_Persistent_TopApp() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(app, PERSISTENT_PROC_ADJ);
doReturn(app).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(null).when(mService).getTopApp();
@@ -388,7 +393,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(app).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(null).when(mService).getTopApp();
@@ -401,8 +406,8 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
- app.mState.setRunningRemoteAnimation(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setRunningRemoteAnimation(app, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
@@ -415,7 +420,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(mock(ActiveInstrumentation.class)).when(app).getActiveInstrumentation();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doCallRealMethod().when(app).getActiveInstrumentation();
@@ -431,7 +436,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(true).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(int[].class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(false).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(int[].class));
@@ -466,8 +471,8 @@
public void testUpdateOomAdj_DoOne_ExecutingService() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.startExecutingService(mock(ServiceRecord.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.startExecutingService(app.mServices, mock(ServiceRecord.class));
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -480,11 +485,11 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
doReturn(app).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(app);
doReturn(null).when(mService).getTopApp();
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, FOREGROUND_APP_ADJ,
SCHED_GROUP_BACKGROUND);
@@ -498,7 +503,7 @@
app.mState.setCurRawAdj(CACHED_APP_MIN_ADJ);
app.mState.setCurAdj(CACHED_APP_MIN_ADJ);
doReturn(null).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -516,7 +521,7 @@
doReturn(true).when(wpc).hasActivities();
doReturn(WindowProcessController.ACTIVITY_STATE_FLAG_IS_VISIBLE)
.when(wpc).getActivityStateFlags();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT);
@@ -555,7 +560,7 @@
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).hasRecentTasks();
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doCallRealMethod().when(wpc).hasRecentTasks();
@@ -567,9 +572,9 @@
public void testUpdateOomAdj_DoOne_FgServiceLocation() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION,
- /* hasNoneType=*/false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(app.mServices, true,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION, /* hasNoneType=*/false);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -582,8 +587,9 @@
public void testUpdateOomAdj_DoOne_FgService() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(app.mServices, true, 0, /* hasNoneType=*/
+ true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -599,20 +605,20 @@
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
- s.startRequested = true;
+ mProcessStateController.setStartRequested(s, true);
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
- s.setShortFgsInfo(SystemClock.uptimeMillis());
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
// SHORT_SERVICE FGS will get IMP_FG and a slightly different recent-adjustment.
{
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.startService(s);
- app.mServices.setHasForegroundServices(true,
+ mProcessStateController.startService(app.mServices, s);
+ mProcessStateController.setHasForegroundServices(app.mServices, true,
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -625,9 +631,9 @@
{
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setHasForegroundServices(true,
+ mProcessStateController.setHasForegroundServices(app.mServices, true,
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
- app.mServices.startService(s);
+ mProcessStateController.startService(app.mServices, s);
app.mState.setLastTopTime(SystemClock.uptimeMillis()
- mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -642,21 +648,21 @@
// SHORT_SERVICE, timed out already.
s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
- s.startRequested = true;
+ mProcessStateController.setStartRequested(s, true);
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
- s.setShortFgsInfo(SystemClock.uptimeMillis()
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis()
- mService.mConstants.mShortFgsTimeoutDuration
- mService.mConstants.mShortFgsProcStateExtraWaitDuration);
{
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setHasForegroundServices(true,
+ mProcessStateController.setHasForegroundServices(app.mServices, true,
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
- app.mServices.startService(s);
+ mProcessStateController.startService(app.mServices, s);
app.mState.setLastTopTime(SystemClock.uptimeMillis()
- mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -671,8 +677,8 @@
public void testUpdateOomAdj_DoOne_OverlayUi() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mState.setHasOverlayUi(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasOverlayUi(app, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
@@ -684,9 +690,10 @@
public void testUpdateOomAdj_DoOne_PerceptibleRecent_FgService() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(app.mServices, true, 0, /* hasNoneType=*/
+ true);
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE,
@@ -699,7 +706,7 @@
verify(mService.mHandler).sendEmptyMessageAtTime(
eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT, "fg-service");
@@ -722,9 +729,9 @@
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
- s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
+ mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s, nowUptime);
s.getConnections().clear();
- app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(app.mServices);
mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -736,7 +743,7 @@
verify(mService.mHandler).sendEmptyMessageAtTime(
eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
? sFirstUiCachedAdj : sFirstCachedAdj;
@@ -758,15 +765,15 @@
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
- s.lastTopAlmostPerceptibleBindRequestUptimeMs =
- nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
- app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s,
+ nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs);
+ mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(app.mServices);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- mService.mOomAdjuster.resetInternal();
+ mProcessStateController.getOomAdjuster().resetInternal();
}
// Out of grace period and no valid binding so no adjustment.
@@ -780,16 +787,16 @@
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
- s.lastTopAlmostPerceptibleBindRequestUptimeMs =
- nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+ mProcessStateController.setLastTopAlmostPerceptibleBindRequest(s,
+ nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs);
s.getConnections().clear();
- app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.updateHasTopStartedAlmostPerceptibleServices(app.mServices);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- mService.mOomAdjuster.resetInternal();
+ mProcessStateController.getOomAdjuster().resetInternal();
}
}
@@ -800,12 +807,12 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
- system.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- system.mState.setHasTopUi(true);
+ mProcessStateController.setMaxAdj(system, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setHasTopUi(system, true);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(system, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -817,8 +824,8 @@
public void testUpdateOomAdj_DoOne_Toast() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mState.setForcingToImportant(new Object());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setForcingToImportant(app, new Object());
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -832,7 +839,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHeavyWeightProcess();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(false).when(wpc).isHeavyWeightProcess();
@@ -847,7 +854,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_HOME, HOME_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -861,7 +868,7 @@
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isPreviousProcess();
doReturn(true).when(wpc).hasActivities();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -873,7 +880,7 @@
verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
? sFirstUiCachedAdj : CACHED_APP_MIN_ADJ;
@@ -896,9 +903,9 @@
doReturn(true).when(wpc).isPreviousProcess();
doReturn(true).when(wpc).hasActivities();
}
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
setProcessesToLru(apps);
- mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
for (int i = 0; i < numberOfApps; i++) {
assertProcStates(apps[i], PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -914,7 +921,7 @@
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
}
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
for (int i = 0; i < numberOfApps; i++) {
final int mruIndex = numberOfApps - i - 1;
@@ -938,10 +945,8 @@
public void testUpdateOomAdj_DoOne_Backup() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
- backupTarget.app = app;
- doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setBackupTarget(app);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(null).when(mService.mBackupTargets).get(anyInt());
@@ -954,8 +959,8 @@
public void testUpdateOomAdj_DoOne_ClientActivities() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setHasClientActivities(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasClientActivities(app.mServices, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.mState.getSetProcState());
@@ -966,8 +971,8 @@
public void testUpdateOomAdj_DoOne_TreatLikeActivity() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- app.mServices.setTreatLikeActivity(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setTreatLikeActivity(app.mServices, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -981,10 +986,10 @@
app.mState.setServiceB(true);
ServiceRecord s = mock(ServiceRecord.class);
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- app.mServices.startService(s);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ mProcessStateController.startService(app.mServices, s);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_B_ADJ, SCHED_GROUP_BACKGROUND);
@@ -995,8 +1000,8 @@
public void testUpdateOomAdj_DoOne_MaxAdj() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- app.mState.setMaxAdj(PERCEPTIBLE_LOW_APP_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(app, PERCEPTIBLE_LOW_APP_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, PERCEPTIBLE_LOW_APP_ADJ,
@@ -1011,7 +1016,7 @@
app.mState.setCurRawAdj(SERVICE_ADJ);
app.mState.setCurAdj(SERVICE_ADJ);
doReturn(null).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.mState.getSetAdj());
@@ -1025,10 +1030,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ServiceRecord s = mock(ServiceRecord.class);
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- app.mServices.startService(s);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ mProcessStateController.startService(app.mServices, s);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -1043,8 +1048,8 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY,
mock(IBinder.class));
- s.startRequested = true;
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(client).when(mService).getTopApp();
updateOomAdj(client, app);
@@ -1062,10 +1067,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- client.mServices.setTreatLikeActivity(true);
+ mProcessStateController.setTreatLikeActivity(client.mServices, true);
bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -1086,7 +1091,7 @@
mock(ActivityServiceConnectionsHolder.class));
doReturn(client).when(mService).getTopApp();
doReturn(true).when(cr.activity).isActivityVisible();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -1099,7 +1104,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
bindService(app, app, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -1114,9 +1119,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- client.mServices.setTreatLikeActivity(true);
+ mProcessStateController.setTreatLikeActivity(client.mServices, true);
bindService(app, client, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_CACHED_EMPTY, app.mState.getSetProcState());
@@ -1137,7 +1142,7 @@
mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(client).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(null).when(mService).getTopApp();
@@ -1152,9 +1157,9 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- client.mState.setHasTopUi(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setHasTopUi(client, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1170,8 +1175,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_IMPORTANT, mock(IBinder.class));
- client.mServices.startExecutingService(mock(ServiceRecord.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.startExecutingService(client.mServices, mock(ServiceRecord.class));
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -1188,7 +1193,7 @@
bindService(app, client, null, null, 0, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(client).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(null).when(mService).getTopApp();
@@ -1203,8 +1208,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.mState.getSetProcState());
@@ -1222,9 +1227,9 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(client, app);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
SCHED_GROUP_RESTRICTED);
@@ -1240,8 +1245,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState());
@@ -1256,8 +1261,9 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
- client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client.mServices, true,
+ 0, /* hasNoneType=*/true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, client.mState.getSetProcState());
@@ -1279,16 +1285,16 @@
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
- s.startRequested = true;
- s.isForeground = true;
- s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
- s.setShortFgsInfo(SystemClock.uptimeMillis());
- client.mServices.startService(s);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setIsForegroundService(s, true);
+ mProcessStateController.setForegroundServiceType(s, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE);
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+ mProcessStateController.startService(client.mServices, s);
client.mState.setLastTopTime(SystemClock.uptimeMillis());
- client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
- /* hasNoneType=*/false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client.mServices, true,
+ FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1310,16 +1316,16 @@
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
- s.startRequested = true;
- s.isForeground = true;
- s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
- s.setShortFgsInfo(SystemClock.uptimeMillis());
- app2.mServices.startService(s);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setIsForegroundService(s, true);
+ mProcessStateController.setForegroundServiceType(s, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE);
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+ mProcessStateController.startService(app2.mServices, s);
app2.mState.setLastTopTime(SystemClock.uptimeMillis());
- app2.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
- /* hasNoneType=*/false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(app2.mServices, true,
+ FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app2);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1331,7 +1337,7 @@
// Persistent process
ProcessRecord pers = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- pers.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(pers, PERSISTENT_PROC_ADJ);
// app1, which is bound by pers (which makes it BFGS)
ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
@@ -1358,18 +1364,16 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
- BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
- backupTarget.app = client;
- doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setBackupTarget(client);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(mService.mBackupTargets).get(anyInt());
+ mProcessStateController.stopBackupTarget(UserHandle.getUserId(MOCKAPP2_UID));
assertEquals(BACKUP_APP_ADJ, app.mState.getSetAdj());
assertNoBfsl(app);
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
updateOomAdj(client, app);
assertEquals(PERSISTENT_SERVICE_ADJ, app.mState.getSetAdj());
@@ -1384,8 +1388,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
- client.mState.setRunningRemoteAnimation(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setRunningRemoteAnimation(client, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj());
@@ -1399,8 +1403,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
- client.mState.setRunningRemoteAnimation(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setRunningRemoteAnimation(client, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1414,8 +1418,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
- client.mState.setHasOverlayUi(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasOverlayUi(client, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1432,13 +1436,13 @@
bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
- mService.mOomAdjuster.resetInternal();
+ mProcessStateController.getOomAdjuster().resetInternal();
}
{
@@ -1451,14 +1455,14 @@
bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
- mService.mOomAdjuster.resetInternal();
+ mProcessStateController.getOomAdjuster().resetInternal();
}
{
@@ -1469,13 +1473,13 @@
bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
- mService.mOomAdjuster.resetInternal();
+ mProcessStateController.getOomAdjuster().resetInternal();
}
{
@@ -1488,14 +1492,14 @@
bindService(app, client, null, null,
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
- mService.mOomAdjuster.resetInternal();
+ mProcessStateController.getOomAdjuster().resetInternal();
}
}
@@ -1507,8 +1511,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
- client.mState.setRunningRemoteAnimation(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setRunningRemoteAnimation(client, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(VISIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1523,8 +1527,8 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_IMPORTANT_BACKGROUND,
mock(IBinder.class));
- client.mState.setHasOverlayUi(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasOverlayUi(client, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.mState.getSetProcState());
@@ -1552,8 +1556,8 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
- client.mServices.setTreatLikeActivity(true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setTreatLikeActivity(client.mServices, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client);
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
@@ -1571,7 +1575,7 @@
bindProvider(app, client, null, null, false);
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(client).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(null).when(mService).getTopApp();
@@ -1585,9 +1589,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
bindProvider(app, client, null, null, false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1607,17 +1611,17 @@
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
- s.startRequested = true;
+ mProcessStateController.setStartRequested(s, true);
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
- s.setShortFgsInfo(SystemClock.uptimeMillis());
- client.mServices.startService(s);
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+ mProcessStateController.startService(client.mServices, s);
client.mState.setLastTopTime(SystemClock.uptimeMillis());
- client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
- /* hasNoneType=*/false);
+ mProcessStateController.setHasForegroundServices(client.mServices, true,
+ FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, false);
bindProvider(app, client, null, null, false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1639,7 +1643,7 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, FOREGROUND_APP_ADJ,
@@ -1652,7 +1656,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
@@ -1664,7 +1668,7 @@
verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
? sFirstNonUiCachedAdj : sFirstCachedAdj;
@@ -1688,7 +1692,7 @@
bindService(client, client2, null, null, 0, mock(IBinder.class));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(client2).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
doReturn(null).when(mService).getTopApp();
@@ -1707,8 +1711,8 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(app, client2, null, null, 0, mock(IBinder.class));
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1727,8 +1731,8 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1747,13 +1751,13 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
bindService(client2, app, null, null, 0, mock(IBinder.class));
// Note: We add processes to LRU but still call updateOomAdjLocked() with a specific
// processes.
setProcessesToLru(app, client, client2);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1766,8 +1770,8 @@
assertBfsl(client);
assertBfsl(client2);
- client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client2.mServices, false, 0, false);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client2);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState());
@@ -1790,8 +1794,8 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client2, client, null, null, 0, mock(IBinder.class));
- client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1817,8 +1821,8 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
bindService(client2, client, null, null, 0, mock(IBinder.class));
- client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1851,8 +1855,8 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
bindService(client3, client4, null, null, 0, mock(IBinder.class));
bindService(client4, client3, null, null, 0, mock(IBinder.class));
- client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1883,13 +1887,13 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
bindService(client2, app, null, null, 0, mock(IBinder.class));
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- client3.mState.setForcingToImportant(new Object());
+ mProcessStateController.setForcingToImportant(client3, new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1913,9 +1917,9 @@
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- client3.mState.setForcingToImportant(new Object());
+ mProcessStateController.setForcingToImportant(client3, new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1940,9 +1944,9 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- client4.mState.setForcingToImportant(new Object());
+ mProcessStateController.setForcingToImportant(client4, new Object());
bindService(app, client4, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1965,13 +1969,13 @@
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- client3.mState.setForcingToImportant(new Object());
+ mProcessStateController.setForcingToImportant(client3, new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
ProcessRecord client4 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- client4.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client4.mServices, true, 0, true);
bindService(app, client4, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1992,12 +1996,12 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(app, client2, null, null, 0, mock(IBinder.class));
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- client3.mState.setForcingToImportant(new Object());
+ mProcessStateController.setForcingToImportant(client3, new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, client3, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2016,8 +2020,8 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2036,9 +2040,9 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
bindService(client2, app, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2057,8 +2061,8 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2077,9 +2081,9 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
bindProvider(client2, app, null, null, false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2102,10 +2106,10 @@
mock(IBinder.class));
bindService(app2, client2, null, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
mock(IBinder.class));
- client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setHasForegroundServices(client2.mServices, true, 0, true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -2126,7 +2130,7 @@
assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
SCHED_GROUP_TOP_APP);
@@ -2136,7 +2140,7 @@
bindService(client2, app1, null, null, 0, mock(IBinder.class));
bindService(app1, client2, null, null, 0, mock(IBinder.class));
- client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
+ mProcessStateController.setHasForegroundServices(client2.mServices, false, 0, false);
updateOomAdj(app1, client1, client2);
assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
SCHED_GROUP_TOP_APP);
@@ -2153,8 +2157,8 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
final ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- client2.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(client2, PERSISTENT_PROC_ADJ);
final ServiceRecord s1 = bindService(app1, client1, null, null,
Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE, mock(IBinder.class));
@@ -2178,10 +2182,10 @@
s2.getConnections().clear();
client1.mServices.removeAllConnections();
client2.mServices.removeAllConnections();
- client1.mState.setMaxAdj(UNKNOWN_ADJ);
- client2.mState.setMaxAdj(UNKNOWN_ADJ);
- client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- client2.mState.setHasOverlayUi(true);
+ mProcessStateController.setMaxAdj(client1, UNKNOWN_ADJ);
+ mProcessStateController.setMaxAdj(client2, UNKNOWN_ADJ);
+ mProcessStateController.setHasForegroundServices(client1.mServices, true, 0, true);
+ mProcessStateController.setHasOverlayUi(client2, true);
bindService(app1, client1, null, s1, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
mock(IBinder.class));
@@ -2196,10 +2200,10 @@
assertProcStates(app2, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
- client2.mState.setHasOverlayUi(false);
+ mProcessStateController.setHasOverlayUi(client2, false);
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(client2).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client2, app2);
assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
@@ -2213,10 +2217,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
final ProcessRecord client1 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
- app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(app1.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
bindService(app1, client1, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
@@ -2234,10 +2238,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
final ProcessRecord client1 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
- client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(client1, PERSISTENT_PROC_ADJ);
- app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setHasForegroundServices(app1.mServices, true, 0, true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
bindService(app1, client1, null, null, Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
@@ -2254,10 +2258,10 @@
public void testUpdateOomAdj_DoOne_PendingFinishAttach() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- app.setPendingFinishAttach(true);
+ mProcessStateController.setPendingFinishAttach(app, true);
app.mState.setHasForegroundActivities(false);
- mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mProcessStateController.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
@@ -2269,11 +2273,11 @@
public void testUpdateOomAdj_DoOne_TopApp_PendingFinishAttach() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- app.setPendingFinishAttach(true);
+ mProcessStateController.setPendingFinishAttach(app, true);
app.mState.setHasForegroundActivities(true);
doReturn(app).when(mService).getTopApp();
- mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mProcessStateController.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ,
@@ -2303,40 +2307,40 @@
client1.setUidRecord(clientUidRecord);
client2.setUidRecord(clientUidRecord);
- client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- client2.mState.setForcingToImportant(new Object());
+ mProcessStateController.setHasForegroundServices(client1.mServices, true, 0, true);
+ mProcessStateController.setForcingToImportant(client2, new Object());
setProcessesToLru(app1, app2, app3, client1, client2);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
final ComponentName cn1 = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
final ServiceRecord s1 = bindService(app1, client1, null, null, 0, mock(IBinder.class));
setFieldValue(ServiceRecord.class, s1, "name", cn1);
- s1.startRequested = true;
+ mProcessStateController.setStartRequested(s1, true);
final ComponentName cn2 = ComponentName.unflattenFromString(
MOCKAPP2_PACKAGENAME + "/.TestService");
final ServiceRecord s2 = bindService(app2, client2, null, null, 0, mock(IBinder.class));
setFieldValue(ServiceRecord.class, s2, "name", cn2);
- s2.startRequested = true;
+ mProcessStateController.setStartRequested(s2, true);
final ComponentName cn3 = ComponentName.unflattenFromString(
MOCKAPP5_PACKAGENAME + "/.TestService");
final ServiceRecord s3 = bindService(app3, client1, null, null, 0, mock(IBinder.class));
setFieldValue(ServiceRecord.class, s3, "name", cn3);
- s3.startRequested = true;
+ mProcessStateController.setStartRequested(s3, true);
final ComponentName cn4 = ComponentName.unflattenFromString(
MOCKAPP3_PACKAGENAME + "/.TestService");
final ServiceRecord c2s = makeServiceRecord(client2);
setFieldValue(ServiceRecord.class, c2s, "name", cn4);
- c2s.startRequested = true;
+ mProcessStateController.setStartRequested(c2s, true);
try {
- mService.mOomAdjuster.mActiveUids.put(MOCKAPP_UID, app1UidRecord);
- mService.mOomAdjuster.mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
- mService.mOomAdjuster.mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
- mService.mOomAdjuster.mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
+ mActiveUids.put(MOCKAPP_UID, app1UidRecord);
+ mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
+ mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
+ mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
setServiceMap(s1, MOCKAPP_UID, cn1);
setServiceMap(s2, MOCKAPP2_UID, cn2);
@@ -2354,8 +2358,8 @@
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app2.mState.getSetProcState());
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, client2.mState.getSetProcState());
- client1.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
- client2.mState.setForcingToImportant(null);
+ mProcessStateController.setHasForegroundServices(client1.mServices, false, 0, false);
+ mProcessStateController.setForcingToImportant(client2, null);
app1UidRecord.reset();
app2UidRecord.reset();
app3UidRecord.reset();
@@ -2379,7 +2383,7 @@
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
mService.mServices.mServiceMap.clear();
- mService.mOomAdjuster.mActiveUids.clear();
+ mActiveUids.clear();
}
}
@@ -2388,12 +2392,13 @@
public void testUpdateOomAdj_DoAll_Unbound() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- app.mState.setForcingToImportant(new Object());
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setForcingToImportant(app, new Object());
+ mProcessStateController.setHasForegroundServices(app2.mServices, true, 0, /* hasNoneType=*/
+ true);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -2408,12 +2413,14 @@
public void testUpdateOomAdj_DoAll_BoundFgService() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
- app.mState.setForcingToImportant(new Object());
ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
- app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+
+ mProcessStateController.setForcingToImportant(app, new Object());
+ mProcessStateController.setHasForegroundServices(app2.mServices, true, 0, /* hasNoneType=*/
+ true);
bindService(app, app2, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2435,9 +2442,9 @@
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(app2, app3, null, null, 0, mock(IBinder.class));
- app3.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(app3.mServices, true, 0, true);
bindService(app3, app, null, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2476,13 +2483,13 @@
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- app4.mState.setHasOverlayUi(true);
+ mProcessStateController.setHasOverlayUi(app4, true);
bindService(app, app4, null, s, 0, mock(IBinder.class));
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2518,13 +2525,13 @@
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- app4.mState.setHasOverlayUi(true);
+ mProcessStateController.setHasOverlayUi(app4, true);
bindService(app, app4, null, s, 0, mock(IBinder.class));
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app5, app4, app3, app2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2560,13 +2567,13 @@
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- app4.mState.setHasOverlayUi(true);
+ mProcessStateController.setHasOverlayUi(app4, true);
bindService(app, app4, null, s, 0, mock(IBinder.class));
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app3, app4, app2, app, app5);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2603,10 +2610,10 @@
mock(IBinder.class));
ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ mProcessStateController.setMaxAdj(client3, PERSISTENT_PROC_ADJ);
bindService(app, client3, null, null, Context.BIND_INCLUDE_CAPABILITIES,
mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
final int expected = PROCESS_CAPABILITY_ALL & ~PROCESS_CAPABILITY_BFSL;
@@ -2631,13 +2638,13 @@
doReturn(true).when(wpc).isHomeProcess();
ProcessRecord app4 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
- app4.mState.setHasOverlayUi(true);
+ mProcessStateController.setHasOverlayUi(app4, true);
bindProvider(app, app4, cr, null, false);
ProcessRecord app5 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
+ mProcessStateController.setHasForegroundServices(app5.mServices, true, 0, true);
bindProvider(app, app5, cr, null, false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2666,22 +2673,22 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
long now = SystemClock.uptimeMillis();
ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
- s.startRequested = true;
- s.lastActivity = now;
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, now);
s = bindService(app2, app, null, null, 0, mock(IBinder.class));
- s.startRequested = true;
- s.lastActivity = now;
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, now);
ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
s = mock(ServiceRecord.class);
- s.app = app3;
+ mProcessStateController.setHostProcess(s, app3);
setFieldValue(ServiceRecord.class, s, "connections",
new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
- app3.mServices.startService(s);
+ mProcessStateController.startService(app3.mServices, s);
doCallRealMethod().when(s).getConnections();
- s.startRequested = true;
- s.lastActivity = now;
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, now);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
mService.mOomAdjuster.mNumServiceProcs = 3;
updateOomAdj(app3, app2, app);
@@ -2702,8 +2709,8 @@
// cachedAdj1 and cachedAdj2 will be read if USE_TIERED_CACHED_ADJ is disabled. Otherwise,
// sFirstUiCachedAdj and sFirstNonUiCachedAdj are used instead.
- final int cachedAdj1 = CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+ final int cachedAdj1 = CACHED_APP_MIN_ADJ + CACHED_APP_IMPORTANCE_LEVELS;
+ final int cachedAdj2 = cachedAdj1 + CACHED_APP_IMPORTANCE_LEVELS * 2;
doReturn(userOwner).when(mService.mUserController).getCurrentUserId();
final ArrayList<ProcessRecord> lru = mService.mProcessList.getLruProcessesLOSP();
@@ -2723,11 +2730,11 @@
ServiceRecord s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
si, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
- s.startRequested = true;
- s.lastActivity = now;
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, now);
- app.mServices.startService(s);
- app.mState.setHasShownUi(true);
+ mProcessStateController.startService(app.mServices, s);
+ mProcessStateController.setHasShownUi(app, true);
final ServiceInfo si2 = mock(ServiceInfo.class);
si2.applicationInfo = mock(ApplicationInfo.class);
@@ -2735,13 +2742,14 @@
ServiceRecord s2 = spy(new ServiceRecord(mService, cn2, cn2, null, 0, null,
si2, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s2).getConnections();
- s2.startRequested = true;
- s2.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ mProcessStateController.setStartRequested(s2, true);
+ mProcessStateController.setServiceLastActivityTime(s2,
+ now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1);
- app2.mServices.startService(s2);
- app2.mState.setHasShownUi(false);
+ mProcessStateController.startService(app2.mServices, s2);
+ mProcessStateController.setHasShownUi(app2, false);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE,
@@ -2754,7 +2762,7 @@
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
- app.mState.setHasShownUi(false);
+ mProcessStateController.setHasShownUi(app, false);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
@@ -2763,27 +2771,28 @@
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
- s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ mProcessStateController.setServiceLastActivityTime(s,
+ now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj1,
SCHED_GROUP_BACKGROUND, "cch-started-services", true);
- app.mServices.stopService(s);
+ mProcessStateController.stopService(app.mServices, s);
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
- app.mState.setHasShownUi(true);
+ mProcessStateController.setHasShownUi(app, true);
mService.mConstants.KEEP_WARMING_SERVICES.add(cn);
mService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
si, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
- s.startRequested = true;
- s.lastActivity = now;
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, now);
- app.mServices.startService(s);
+ mProcessStateController.startService(app.mServices, s);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
@@ -2795,8 +2804,9 @@
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
- app.mState.setHasShownUi(false);
- s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ mProcessStateController.setHasShownUi(app, false);
+ mProcessStateController.setServiceLastActivityTime(s,
+ now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
@@ -2825,7 +2835,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(app).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2847,7 +2857,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(app).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2873,14 +2883,14 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
long now = SystemClock.uptimeMillis();
ServiceRecord s = bindService(app, app2, null, null, 0, mock(IBinder.class));
- s.startRequested = true;
- s.lastActivity = now;
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, now);
s = bindService(app2, app3, null, null, 0, mock(IBinder.class));
- s.lastActivity = now;
+ mProcessStateController.setServiceLastActivityTime(s, now);
s = bindService(app3, app2, null, null, 0, mock(IBinder.class));
- s.lastActivity = now;
+ mProcessStateController.setServiceLastActivityTime(s, now);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
mService.mOomAdjuster.mNumServiceProcs = 3;
updateOomAdj(app, app2, app3);
@@ -2898,14 +2908,14 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
doReturn(app).when(mService).getTopApp();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
// Start binding to a service that isn't running yet.
ServiceRecord sr = makeServiceRecord(app);
- sr.app = null;
+ mProcessStateController.setHostProcess(sr, null);
bindService(null, app, null, sr, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
// Since sr.app is null, this service cannot be in the same process as the
@@ -2924,13 +2934,13 @@
setProcessesToLru(app);
ServiceRecord s = makeServiceRecord(app);
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
- app.mServices.stopService(s);
+ mProcessStateController.stopService(app.mServices, s);
updateOomAdj();
// isolated process should be killed immediately after service stop.
verify(app).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -2944,13 +2954,13 @@
MOCKAPP_ISOLATED_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ServiceRecord s = makeServiceRecord(app);
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdjPending(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
- app.mServices.stopService(s);
+ mProcessStateController.stopService(app.mServices, s);
updateOomAdjPending(app);
// isolated process should be killed immediately after service stop.
verify(app).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -2966,13 +2976,13 @@
setProcessesToLru(app);
ServiceRecord s = makeServiceRecord(app);
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
- app.mServices.stopService(s);
+ mProcessStateController.stopService(app.mServices, s);
updateOomAdj();
// isolated process with entry point should not be killed
verify(app, never()).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -2987,13 +2997,13 @@
app.setIsolatedEntryPoint("test");
ServiceRecord s = makeServiceRecord(app);
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdjPending(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
- app.mServices.stopService(s);
+ mProcessStateController.stopService(app.mServices, s);
updateOomAdjPending(app);
// isolated process with entry point should not be killed
verify(app, never()).killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER,
@@ -3014,10 +3024,10 @@
setProcessesToLru(sandboxService, client, attributedClient);
- client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- attributedClient.mServices.setHasForegroundServices(true, 0, true);
+ mProcessStateController.setMaxAdj(client, PERSISTENT_PROC_ADJ);
+ mProcessStateController.setHasForegroundServices(attributedClient.mServices, true, 0, true);
bindService(sandboxService, client, attributedClient, null, 0, mock(IBinder.class));
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(client, PROCESS_STATE_PERSISTENT, PERSISTENT_PROC_ADJ,
SCHED_GROUP_DEFAULT);
@@ -3038,13 +3048,13 @@
// App1 binds to app2 and gets temp allowlisted.
bindService(app2, app, null, null, 0, mock(IBinder.class));
- mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+ mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app.mOptRecord.shouldNotFreeze());
assertEquals(true, app2.mOptRecord.shouldNotFreeze());
- mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+ mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
assertEquals(false, app2.mOptRecord.shouldNotFreeze());
@@ -3064,8 +3074,8 @@
// App1 and app2 both bind to app3 and get temp allowlisted.
bindService(app3, app, null, null, 0, mock(IBinder.class));
bindService(app3, app2, null, null, 0, mock(IBinder.class));
- mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
- mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
+ mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+ mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
@@ -3074,7 +3084,7 @@
assertEquals(true, app3.mOptRecord.shouldNotFreeze());
// Remove app1 from allowlist.
- mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+ mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -3082,7 +3092,7 @@
assertEquals(true, app3.mOptRecord.shouldNotFreeze());
// Now remove app2 from allowlist.
- mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
+ mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app2.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -3098,9 +3108,9 @@
setProcessesToLru(app);
ServiceRecord s = makeServiceRecord(app);
- s.startRequested = true;
- s.lastActivity = SystemClock.uptimeMillis();
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mProcessStateController.setStartRequested(s, true);
+ mProcessStateController.setServiceLastActivityTime(s, SystemClock.uptimeMillis());
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
"started-services");
@@ -3111,7 +3121,7 @@
verify(mService.mHandler).sendEmptyMessageAtTime(
eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
? sFirstNonUiCachedAdj : sFirstCachedAdj;
@@ -3131,9 +3141,9 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
app1.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
app2.mProviders.setLastProviderTime(SystemClock.uptimeMillis() + 2000);
- mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
setProcessesToLru(app1, app2);
- mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ mProcessStateController.runFullUpdate(OOM_ADJ_REASON_NONE);
assertProcStates(app1, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
SCHED_GROUP_BACKGROUND, "recent-provider");
@@ -3146,7 +3156,7 @@
verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
final int expectedAdj = mService.mConstants.USE_TIERED_CACHED_ADJ
? sFirstNonUiCachedAdj : sFirstCachedAdj;
@@ -3156,7 +3166,7 @@
verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
- mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ mProcessStateController.runFollowUpUpdate();
assertProcStates(app2, PROCESS_STATE_CACHED_EMPTY, expectedAdj, SCHED_GROUP_BACKGROUND,
"cch-empty");
}
@@ -3169,12 +3179,12 @@
private ServiceRecord makeServiceRecord(ProcessRecord app) {
final ServiceRecord record = mock(ServiceRecord.class);
- record.app = app;
+ mProcessStateController.setHostProcess(record, app);
setFieldValue(ServiceRecord.class, record, "connections",
new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
doCallRealMethod().when(record).getConnections();
setFieldValue(ServiceRecord.class, record, "packageName", app.info.packageName);
- app.mServices.startService(record);
+ mProcessStateController.startService(app.mServices, record);
record.appInfo = app.info;
setFieldValue(ServiceRecord.class, record, "bindings", new ArrayMap<>());
setFieldValue(ServiceRecord.class, record, "pendingStarts", new ArrayList<>());
@@ -3213,17 +3223,36 @@
doCallRealMethod().when(record).addConnection(any(IBinder.class),
any(ConnectionRecord.class));
record.addConnection(binder, cr);
- client.mServices.addConnection(cr);
+ mProcessStateController.addConnection(client.mServices, cr);
binding.connections.add(cr);
doNothing().when(cr).trackProcState(anyInt(), anyInt());
return record;
}
+ private void setWakefulness(int state) {
+ if (Flags.pushGlobalStateToOomadjuster()) {
+ mProcessStateController.setWakefulness(state);
+ } else {
+ mService.mWakefulness.set(state);
+ }
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private void setBackupTarget(ProcessRecord app) {
+ if (Flags.pushGlobalStateToOomadjuster()) {
+ mProcessStateController.setBackupTarget(app, app.userId);
+ } else {
+ BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
+ backupTarget.app = app;
+ doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
+ }
+ }
+
private ContentProviderRecord bindProvider(ProcessRecord publisher, ProcessRecord client,
ContentProviderRecord record, String name, boolean hasExternalProviders) {
if (record == null) {
record = mock(ContentProviderRecord.class);
- publisher.mProviders.installProvider(name, record);
+ mProcessStateController.addPublishedProvider(publisher, name, record);
record.proc = publisher;
setFieldValue(ContentProviderRecord.class, record, "connections",
new ArrayList<ContentProviderConnection>());
@@ -3232,7 +3261,7 @@
ContentProviderConnection conn = spy(new ContentProviderConnection(record, client,
client.info.packageName, UserHandle.getUserId(client.uid)));
record.connections.add(conn);
- client.mProviders.addProviderConnection(conn);
+ mProcessStateController.addProviderConnection(client, conn);
return record;
}
@@ -3405,10 +3434,10 @@
}
providers.setLastProviderTime(mLastProviderTime);
- UidRecord uidRec = mService.mOomAdjuster.mActiveUids.get(mUid);
+ UidRecord uidRec = mActiveUids.get(mUid);
if (uidRec == null) {
uidRec = new UidRecord(mUid, mService);
- mService.mOomAdjuster.mActiveUids.put(mUid, uidRec);
+ mActiveUids.put(mUid, uidRec);
}
uidRec.addProcess(app);
app.setUidRecord(uidRec);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
index 1ff4a27..59302ee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -50,7 +50,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
@@ -169,6 +168,7 @@
realAtm.initialize(null, null, mContext.getMainLooper());
realAms.mActivityTaskManager = spy(realAtm);
realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
+ realAms.mProcessStateController = spy(realAms.mProcessStateController);
realAms.mOomAdjuster = spy(realAms.mOomAdjuster);
realAms.mOomAdjuster.mCachedAppOptimizer = spy(realAms.mOomAdjuster.mCachedAppOptimizer);
realAms.mPackageManagerInt = mPackageManagerInt;
@@ -242,14 +242,14 @@
USER_SYSTEM // userId
));
- verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
- clearInvocations(mAms.mOomAdjuster);
+ verify(mAms.mProcessStateController, bindMode).runPendingUpdate(anyInt());
+ clearInvocations(mAms.mProcessStateController);
// Unbind the service.
mAms.unbindService(serviceConnection);
- verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
- clearInvocations(mAms.mOomAdjuster);
+ verify(mAms.mProcessStateController, unbindMode).runPendingUpdate(anyInt());
+ clearInvocations(mAms.mProcessStateController);
removeProcessRecord(app);
}
@@ -496,8 +496,8 @@
USER_SYSTEM // userId
));
- verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
- clearInvocations(mAms.mOomAdjuster);
+ verify(mAms.mProcessStateController, bindMode).runPendingUpdate(anyInt());
+ clearInvocations(mAms.mProcessStateController);
if (clientApp.isFreezable()) {
verify(mAms.mOomAdjuster.mCachedAppOptimizer,
@@ -509,8 +509,8 @@
// Unbind the service.
mAms.unbindService(serviceConnection);
- verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
- clearInvocations(mAms.mOomAdjuster);
+ verify(mAms.mProcessStateController, unbindMode).runPendingUpdate(anyInt());
+ clearInvocations(mAms.mProcessStateController);
removeProcessRecord(clientApp);
removeProcessRecord(serviceApp);
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index d6ca10a..d9e071f 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -27,6 +27,9 @@
"servicestests-utils",
"platform-test-annotations",
"flag-junit",
+ "statsdprotolite",
+ "StatsdTestUtils",
+ "platformprotoslite",
],
libs: [
@@ -74,6 +77,10 @@
"src/com/android/server/power/stats/format/*.java",
"src/com/android/server/power/stats/processor/*.java",
],
+ // TODO(b/372292543): Enable this test.
+ exclude_srcs: [
+ "src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java",
+ ],
java_resources: [
"res/xml/power_profile*.xml",
],
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java
new file mode 100644
index 0000000..cb644db
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockStatsFrameworkEventsTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2024 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.server.power.stats;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.WakeLockLevelEnum;
+import android.util.StatsEvent;
+import android.util.StatsEventTestUtils;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.os.AtomsProto;
+import com.android.os.framework.FrameworkExtensionAtoms;
+import com.android.os.framework.FrameworkExtensionAtoms.FrameworkWakelockInfo;
+
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.CodedOutputStream;
+import com.google.protobuf.ExtensionRegistryLite;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WakelockStatsFrameworkEventsTest {
+ private WakelockStatsFrameworkEvents mEvents;
+ private ExtensionRegistryLite mRegistry;
+
+ @Before
+ public void setup() {
+ mEvents = new WakelockStatsFrameworkEvents();
+ mRegistry = ExtensionRegistryLite.newInstance();
+ FrameworkExtensionAtoms.registerAllExtensions(mRegistry);
+ }
+
+ private static final int UID_1 = 1;
+ private static final int UID_2 = 2;
+
+ private static final String TAG_1 = "TAG1";
+ private static final String TAG_2 = "TAG2";
+
+ private static final WakeLockLevelEnum WAKELOCK_TYPE_1 = WakeLockLevelEnum.PARTIAL_WAKE_LOCK;
+ private static final WakeLockLevelEnum WAKELOCK_TYPE_2 = WakeLockLevelEnum.DOZE_WAKE_LOCK;
+
+ private static final long TS_1 = 1000;
+ private static final long TS_2 = 2000;
+ private static final long TS_3 = 3000;
+ private static final long TS_4 = 4000;
+ private static final long TS_5 = 5000;
+
+ // Assumes that mEvents is empty.
+ private void makeMetricsAlmostOverflow() throws Exception {
+ for (int i = 0; i < mEvents.SUMMARY_THRESHOLD - 1; i++) {
+ String tag = "forceOverflow" + i;
+ mEvents.noteStartWakeLock(UID_1, tag, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(UID_1, tag, WAKELOCK_TYPE_1.getNumber(), TS_2);
+ }
+
+ assertFalse("not overflow", mEvents.inOverflow());
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+ FrameworkWakelockInfo notOverflowInfo =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(mEvents.OVERFLOW_TAG))
+ .findFirst()
+ .orElse(null);
+
+ assertEquals("not overflow", notOverflowInfo, null);
+
+ // Add one more to hit an overflow state.
+ String lastTag = "forceOverflowLast";
+ mEvents.noteStartWakeLock(UID_1, lastTag, WAKELOCK_TYPE_2.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(UID_1, lastTag, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+ assertTrue("overflow", mEvents.inOverflow());
+ info = pullResults(TS_4);
+
+ FrameworkWakelockInfo tag1Info =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(lastTag))
+ .findFirst()
+ .orElse(null);
+
+ assertTrue("lastTag found", tag1Info != null);
+ assertEquals("uid", UID_1, tag1Info.getAttributionUid());
+ assertEquals("tag", lastTag, tag1Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_2, tag1Info.getType());
+ assertEquals("duration", TS_2 - TS_1, tag1Info.getUptimeMillis());
+ assertEquals("count", 1, tag1Info.getCompletedCount());
+ }
+
+ // Assumes that mEvents is empty.
+ private void makeMetricsAlmostHardCap() throws Exception {
+ for (int i = 0; i < mEvents.MAX_WAKELOCK_DIMENSIONS - 1; i++) {
+ mEvents.noteStartWakeLock(i /* uid */, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(i /* uid */, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+ }
+
+ assertFalse("not hard capped", mEvents.inHardCap());
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+ FrameworkWakelockInfo notOverflowInfo =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(mEvents.HARD_CAP_TAG))
+ .findFirst()
+ .orElse(null);
+
+ assertEquals("not overflow", notOverflowInfo, null);
+
+ // Add one more to hit an hardcap state.
+ int hardCapUid = mEvents.MAX_WAKELOCK_DIMENSIONS;
+ mEvents.noteStartWakeLock(hardCapUid, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(hardCapUid, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+ assertTrue("hard capped", mEvents.inHardCap());
+ info = pullResults(TS_4);
+
+ FrameworkWakelockInfo tag2Info =
+ info.stream()
+ .filter(i -> i.getAttributionUid() == hardCapUid)
+ .findFirst()
+ .orElse(null);
+
+ assertTrue("hardCapUid found", tag2Info != null);
+ assertEquals("uid", hardCapUid, tag2Info.getAttributionUid());
+ assertEquals("tag", mEvents.OVERFLOW_TAG, tag2Info.getAttributionTag());
+ assertEquals(
+ "type", WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL), tag2Info.getType());
+ assertEquals("duration", TS_2 - TS_1, tag2Info.getUptimeMillis());
+ assertEquals("count", 1, tag2Info.getCompletedCount());
+ }
+
+ private ArrayList<FrameworkWakelockInfo> pullResults(long timestamp) throws Exception {
+ ArrayList<FrameworkWakelockInfo> result = new ArrayList<>();
+ List<StatsEvent> events = mEvents.pullFrameworkWakelockInfoAtoms(timestamp);
+
+ for (StatsEvent e : events) {
+ // The returned atom does not have external extensions registered.
+ // So we serialize and then deserialize with extensions registered.
+ AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(e);
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ CodedOutputStream codedos = CodedOutputStream.newInstance(outputStream);
+ atom.writeTo(codedos);
+ codedos.flush();
+
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ CodedInputStream codedis = CodedInputStream.newInstance(inputStream);
+ AtomsProto.Atom atomWithExtensions = AtomsProto.Atom.parseFrom(codedis, mRegistry);
+
+ assertTrue(
+ atomWithExtensions.hasExtension(FrameworkExtensionAtoms.frameworkWakelockInfo));
+ FrameworkWakelockInfo info =
+ atomWithExtensions.getExtension(FrameworkExtensionAtoms.frameworkWakelockInfo);
+ result.add(info);
+ }
+
+ return result;
+ }
+
+ @Test
+ public void singleWakelock() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_3);
+
+ assertEquals("size", 1, info.size());
+ assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+ assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+ assertEquals("duration", TS_2 - TS_1, info.get(0).getUptimeMillis());
+ assertEquals("count", 1, info.get(0).getCompletedCount());
+ }
+
+ @Test
+ public void wakelockOpen() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_3);
+
+ assertEquals("size", 1, info.size());
+ assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+ assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+ assertEquals("duration", TS_3 - TS_1, info.get(0).getUptimeMillis());
+ assertEquals("count", 0, info.get(0).getCompletedCount());
+ }
+
+ @Test
+ public void wakelockOpenOverlap() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_3);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+
+ assertEquals("size", 1, info.size());
+ assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+ assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+ assertEquals("duration", TS_4 - TS_1, info.get(0).getUptimeMillis());
+ assertEquals("count", 0, info.get(0).getCompletedCount());
+ }
+
+ @Test
+ public void testOverflow() throws Exception {
+ makeMetricsAlmostOverflow();
+
+ // This one gets tagged as an overflow.
+ mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+ FrameworkWakelockInfo overflowInfo =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(mEvents.OVERFLOW_TAG))
+ .findFirst()
+ .orElse(null);
+
+ assertEquals("uid", UID_1, overflowInfo.getAttributionUid());
+ assertEquals(
+ "type",
+ WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+ overflowInfo.getType());
+ assertEquals("duration", TS_2 - TS_1, overflowInfo.getUptimeMillis());
+ assertEquals("count", 1, overflowInfo.getCompletedCount());
+ }
+
+ @Test
+ public void testOverflowOpen() throws Exception {
+ makeMetricsAlmostOverflow();
+
+ // This is the open wakelock that overflows.
+ mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+ FrameworkWakelockInfo overflowInfo =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(mEvents.OVERFLOW_TAG))
+ .findFirst()
+ .orElse(null);
+
+ assertEquals("uid", UID_1, overflowInfo.getAttributionUid());
+ assertEquals(
+ "type",
+ WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+ overflowInfo.getType());
+ assertEquals("duration", (TS_4 - TS_1), overflowInfo.getUptimeMillis());
+ assertEquals("count", 0, overflowInfo.getCompletedCount());
+ }
+
+ @Test
+ public void testHardCap() throws Exception {
+ makeMetricsAlmostHardCap();
+
+ // This one gets tagged as a hard cap.
+ mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+ mEvents.noteStopWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_2);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+ FrameworkWakelockInfo hardCapInfo =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(mEvents.HARD_CAP_TAG))
+ .findFirst()
+ .orElse(null);
+
+ assertEquals("uid", mEvents.HARD_CAP_UID, hardCapInfo.getAttributionUid());
+ assertEquals(
+ "type",
+ WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+ hardCapInfo.getType());
+ assertEquals("duration", TS_2 - TS_1, hardCapInfo.getUptimeMillis());
+ assertEquals("count", 1, hardCapInfo.getCompletedCount());
+ }
+
+ @Test
+ public void testHardCapOpen() throws Exception {
+ makeMetricsAlmostHardCap();
+
+ // This is the open wakelock that overflows.
+ mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_2.getNumber(), TS_1);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_4);
+ FrameworkWakelockInfo hardCapInfo =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(mEvents.HARD_CAP_TAG))
+ .findFirst()
+ .orElse(null);
+
+ assertEquals("uid", mEvents.HARD_CAP_UID, hardCapInfo.getAttributionUid());
+ assertEquals(
+ "type",
+ WakeLockLevelEnum.forNumber(mEvents.OVERFLOW_LEVEL),
+ hardCapInfo.getType());
+ assertEquals("duration", (TS_4 - TS_1), hardCapInfo.getUptimeMillis());
+ assertEquals("count", 0, hardCapInfo.getCompletedCount());
+ }
+
+ @Test
+ public void overlappingWakelocks() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_3);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+
+ assertEquals("size", 1, info.size());
+ assertEquals("uid", UID_1, info.get(0).getAttributionUid());
+ assertEquals("tag", TAG_1, info.get(0).getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, info.get(0).getType());
+ assertEquals("duration", TS_4 - TS_1, info.get(0).getUptimeMillis());
+ assertEquals("count", 1, info.get(0).getCompletedCount());
+ }
+
+ @Test
+ public void diffUid() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStartWakeLock(UID_2, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_2);
+ mEvents.noteStopWakeLock(UID_2, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_3);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+ assertEquals("size", 2, info.size());
+
+ FrameworkWakelockInfo uid1Info =
+ info.stream().filter(i -> i.getAttributionUid() == UID_1).findFirst().orElse(null);
+
+ assertTrue("UID_1 found", uid1Info != null);
+ assertEquals("uid", UID_1, uid1Info.getAttributionUid());
+ assertEquals("tag", TAG_1, uid1Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, uid1Info.getType());
+ assertEquals("duration", TS_4 - TS_1, uid1Info.getUptimeMillis());
+ assertEquals("count", 1, uid1Info.getCompletedCount());
+
+ FrameworkWakelockInfo uid2Info =
+ info.stream().filter(i -> i.getAttributionUid() == UID_2).findFirst().orElse(null);
+ assertTrue("UID_2 found", uid2Info != null);
+ assertEquals("uid", UID_2, uid2Info.getAttributionUid());
+ assertEquals("tag", TAG_1, uid2Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, uid2Info.getType());
+ assertEquals("duration", TS_3 - TS_2, uid2Info.getUptimeMillis());
+ assertEquals("count", 1, uid2Info.getCompletedCount());
+ }
+
+ @Test
+ public void diffTag() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStartWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_1.getNumber(), TS_2);
+ mEvents.noteStopWakeLock(UID_1, TAG_2, WAKELOCK_TYPE_1.getNumber(), TS_3);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+ assertEquals("size", 2, info.size());
+
+ FrameworkWakelockInfo uid1Info =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(TAG_1))
+ .findFirst()
+ .orElse(null);
+
+ assertTrue("TAG_1 found", uid1Info != null);
+ assertEquals("uid", UID_1, uid1Info.getAttributionUid());
+ assertEquals("tag", TAG_1, uid1Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, uid1Info.getType());
+ assertEquals("duration", TS_4 - TS_1, uid1Info.getUptimeMillis());
+ assertEquals("count", 1, uid1Info.getCompletedCount());
+
+ FrameworkWakelockInfo uid2Info =
+ info.stream()
+ .filter(i -> i.getAttributionTag().equals(TAG_2))
+ .findFirst()
+ .orElse(null);
+ assertTrue("TAG_2 found", uid2Info != null);
+ assertEquals("uid", UID_1, uid2Info.getAttributionUid());
+ assertEquals("tag", TAG_2, uid2Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, uid2Info.getType());
+ assertEquals("duration", TS_3 - TS_2, uid2Info.getUptimeMillis());
+ assertEquals("count", 1, uid2Info.getCompletedCount());
+ }
+
+ @Test
+ public void diffType() throws Exception {
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_1);
+ mEvents.noteStartWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_2.getNumber(), TS_2);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_2.getNumber(), TS_3);
+ mEvents.noteStopWakeLock(UID_1, TAG_1, WAKELOCK_TYPE_1.getNumber(), TS_4);
+
+ ArrayList<FrameworkWakelockInfo> info = pullResults(TS_5);
+ assertEquals("size", 2, info.size());
+
+ FrameworkWakelockInfo uid1Info =
+ info.stream().filter(i -> i.getType() == WAKELOCK_TYPE_1).findFirst().orElse(null);
+
+ assertTrue("WAKELOCK_TYPE_1 found", uid1Info != null);
+ assertEquals("uid", UID_1, uid1Info.getAttributionUid());
+ assertEquals("tag", TAG_1, uid1Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_1, uid1Info.getType());
+ assertEquals("duration", TS_4 - TS_1, uid1Info.getUptimeMillis());
+ assertEquals("count", 1, uid1Info.getCompletedCount());
+
+ FrameworkWakelockInfo uid2Info =
+ info.stream().filter(i -> i.getType() == WAKELOCK_TYPE_2).findFirst().orElse(null);
+ assertTrue("WAKELOCK_TYPE_2 found", uid2Info != null);
+ assertEquals("uid", UID_1, uid2Info.getAttributionUid());
+ assertEquals("tag", TAG_1, uid2Info.getAttributionTag());
+ assertEquals("type", WAKELOCK_TYPE_2, uid2Info.getType());
+ assertEquals("duration", TS_3 - TS_2, uid2Info.getUptimeMillis());
+ assertEquals("count", 1, uid2Info.getCompletedCount());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index 31bf5f0..4981ceb 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -61,6 +61,7 @@
private static final long USAGE_STATS_INTERACTION = 10 * 60 * 1000L;
private static final long SERVICE_USAGE_INTERACTION = 60 * 1000;
+ @SuppressWarnings("GuardedBy")
@BeforeClass
public static void setUpOnce() {
sContext = getInstrumentation().getTargetContext();
@@ -92,8 +93,11 @@
return true;
}
};
- sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null,
- injector);
+ sService.mProcessStateController = new ProcessStateController.Builder(sService,
+ sService.mProcessList, null)
+ .setOomAdjusterInjector(injector)
+ .build();
+ sService.mOomAdjuster = sService.mProcessStateController.getOomAdjuster();
LocalServices.addService(UsageStatsManagerInternal.class,
mock(UsageStatsManagerInternal.class));
sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index e6c34ca..62f5edc 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -1999,7 +1999,8 @@
/* tag= */ null, MacAddress.BROADCAST_ADDRESS, displayName, deviceProfile,
/* associatedDevice= */ null, /* selfManaged= */ true,
/* notifyOnDeviceNearby= */ false, /* revoked= */ false, /* pending= */ false,
- /* timeApprovedMs= */0, /* lastTimeConnectedMs= */0, /* systemDataSyncFlags= */ -1);
+ /* timeApprovedMs= */0, /* lastTimeConnectedMs= */0,
+ /* systemDataSyncFlags= */ -1, /* deviceIcon= */ null);
}
/** Helper class to drop permissions temporarily and restore them at the end of a test. */
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 733f056..b565f4b 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -24,13 +24,9 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertThrows;
-import android.annotation.NonNull;
+import android.content.Context;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateRequest;
@@ -40,9 +36,10 @@
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
-import androidx.test.InstrumentationRegistry;
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.PollingCheck;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -63,16 +60,25 @@
/**
* Unit tests for {@link DeviceStateManagerService}.
- * <p/>
- * Run with <code>atest DeviceStateManagerServiceTest</code>.
+ *
+ * <p> Build/Install/Run:
+ * atest FrameworksServicesTests:DeviceStateManagerServiceTest
*/
@Presubmit
@RunWith(AndroidJUnit4.class)
public final class DeviceStateManagerServiceTest {
private static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(
new DeviceState.Configuration.Builder(0, "DEFAULT").build());
+ private static final int DEFAULT_DEVICE_STATE_IDENTIFIER = DEFAULT_DEVICE_STATE.getIdentifier();
+ private static final String DEFAULT_DEVICE_STATE_TRACE_STRING =
+ DEFAULT_DEVICE_STATE_IDENTIFIER + ":" + DEFAULT_DEVICE_STATE.getName();
+
private static final DeviceState OTHER_DEVICE_STATE = new DeviceState(
new DeviceState.Configuration.Builder(1, "DEFAULT").build());
+ private static final int OTHER_DEVICE_STATE_IDENTIFIER = OTHER_DEVICE_STATE.getIdentifier();
+ private static final String OTHER_DEVICE_STATE_TRACE_STRING =
+ OTHER_DEVICE_STATE_IDENTIFIER + ":" + OTHER_DEVICE_STATE.getName();
+
private static final DeviceState DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP =
new DeviceState(new DeviceState.Configuration.Builder(2,
"DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP")
@@ -93,24 +99,29 @@
private static final int TIMEOUT = 2000;
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ @NonNull
private TestDeviceStatePolicy mPolicy;
+ @NonNull
private TestDeviceStateProvider mProvider;
+ @NonNull
private DeviceStateManagerService mService;
+ @NonNull
private TestSystemPropertySetter mSysPropSetter;
+ @NonNull
private WindowProcessController mWindowProcessController;
@Before
public void setup() {
mProvider = new TestDeviceStateProvider();
- mPolicy = new TestDeviceStatePolicy(mProvider);
+ mPolicy = new TestDeviceStatePolicy(mContext, mProvider);
mSysPropSetter = new TestSystemPropertySetter();
setupDeviceStateManagerService();
flushHandler(); // Flush the handler to ensure the initial values are committed.
}
private void setupDeviceStateManagerService() {
- mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy,
- mSysPropSetter);
+ mService = new DeviceStateManagerService(mContext, mPolicy, mSysPropSetter);
// Necessary to allow us to check for top app process id in tests
mService.mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
@@ -136,56 +147,53 @@
@Test
public void baseStateChanged() {
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
flushHandler();
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
}
@Test
public void baseStateChanged_withStatePendingPolicyCallback() {
mPolicy.blockConfigure();
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
flushHandler();
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
- mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
+ mProvider.setState(DEFAULT_DEVICE_STATE_IDENTIFIER);
flushHandler();
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
mPolicy.resumeConfigure();
flushHandler();
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
}
@Test
@@ -194,13 +202,12 @@
mProvider.setState(UNSUPPORTED_DEVICE_STATE.getIdentifier());
});
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
}
@Test
@@ -208,25 +215,23 @@
assertThrows(IllegalArgumentException.class,
() -> mProvider.setState(INVALID_DEVICE_STATE_IDENTIFIER));
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
}
@Test
public void supportedStatesChanged() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE,
OTHER_DEVICE_STATE, DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
@@ -235,30 +240,29 @@
// The current committed and requests states do not change because the current state remains
// supported.
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE);
- assertEquals(callback.getLastNotifiedInfo().supportedStates, List.of(DEFAULT_DEVICE_STATE));
+ assertThat(callback.getLastNotifiedInfo().supportedStates)
+ .containsExactly(DEFAULT_DEVICE_STATE);
}
@Test
public void supportedStatesChanged_statesRemainSame() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
// An initial callback will be triggered on registration, so we clear it here.
flushHandler();
callback.clearLastNotifiedInfo();
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE,
OTHER_DEVICE_STATE, DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
@@ -268,26 +272,26 @@
// The current committed and requests states do not change because the current state remains
// supported.
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
assertThat(mService.getSupportedStates()).containsExactly(DEFAULT_DEVICE_STATE,
OTHER_DEVICE_STATE, DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
// The callback wasn't notified about a change in supported states as the states have not
// changed.
- assertNull(callback.getLastNotifiedInfo());
+ assertThat(callback.getLastNotifiedInfo()).isNull();
}
@Test
public void getDeviceStateInfo() throws RemoteException {
- DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
- assertNotNull(info);
- assertEquals(info.supportedStates, SUPPORTED_DEVICE_STATES);
- assertEquals(info.baseState, DEFAULT_DEVICE_STATE);
- assertEquals(info.currentState, DEFAULT_DEVICE_STATE);
+ final DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+ assertThat(info).isNotNull();
+ assertThat(info.supportedStates)
+ .containsExactlyElementsIn(SUPPORTED_DEVICE_STATES).inOrder();
+ assertThat(info.baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+ assertThat(info.currentState).isEqualTo(DEFAULT_DEVICE_STATE);
}
@FlakyTest(bugId = 297949293)
@@ -295,105 +299,109 @@
public void getDeviceStateInfo_baseStateAndCommittedStateNotSet() throws RemoteException {
// Create a provider and a service without an initial base state.
mProvider = new TestDeviceStateProvider(null /* initialState */);
- mPolicy = new TestDeviceStatePolicy(mProvider);
+ mPolicy = new TestDeviceStatePolicy(mContext, mProvider);
setupDeviceStateManagerService();
flushHandler(); // Flush the handler to ensure the initial values are committed.
- DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+ final DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
- assertEquals(info.supportedStates, SUPPORTED_DEVICE_STATES);
- assertEquals(info.baseState.getIdentifier(), INVALID_DEVICE_STATE_IDENTIFIER);
- assertEquals(info.currentState.getIdentifier(), INVALID_DEVICE_STATE_IDENTIFIER);
+ assertThat(info.supportedStates)
+ .containsExactlyElementsIn(SUPPORTED_DEVICE_STATES).inOrder();
+ assertThat(info.baseState.getIdentifier()).isEqualTo(INVALID_DEVICE_STATE_IDENTIFIER);
+ assertThat(info.currentState.getIdentifier()).isEqualTo(INVALID_DEVICE_STATE_IDENTIFIER);
}
@Test
public void registerCallback() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
- == OTHER_DEVICE_STATE.getIdentifier());
+ == OTHER_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
- == OTHER_DEVICE_STATE.getIdentifier());
+ == OTHER_DEVICE_STATE_IDENTIFIER);
- mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
+ mProvider.setState(DEFAULT_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
- == DEFAULT_DEVICE_STATE.getIdentifier());
-
+ == DEFAULT_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
- == DEFAULT_DEVICE_STATE.getIdentifier());
+ == DEFAULT_DEVICE_STATE_IDENTIFIER);
mPolicy.blockConfigure();
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
// The callback should not have been notified of the state change as the policy is still
// pending callback.
waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
- == DEFAULT_DEVICE_STATE.getIdentifier());
+ == DEFAULT_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
- == DEFAULT_DEVICE_STATE.getIdentifier());
+ == DEFAULT_DEVICE_STATE_IDENTIFIER);
mPolicy.resumeConfigure();
// Now that the policy is finished processing the callback should be notified of the state
// change.
waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
- == OTHER_DEVICE_STATE.getIdentifier());
+ == OTHER_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().currentState.getIdentifier()
- == OTHER_DEVICE_STATE.getIdentifier());
+ == OTHER_DEVICE_STATE_IDENTIFIER);
}
@Test
- public void registerCallback_emitsInitialValue() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ public void registerCallback_initialValueAvailable_emitsDeviceState() throws RemoteException {
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+
mService.getBinderService().registerCallback(callback);
flushHandler();
- assertNotNull(callback.getLastNotifiedInfo());
- assertEquals(callback.getLastNotifiedInfo().baseState, DEFAULT_DEVICE_STATE);
- assertEquals(callback.getLastNotifiedInfo().currentState, DEFAULT_DEVICE_STATE);
+ final DeviceStateInfo stateInfo = callback.getLastNotifiedInfo();
+
+ assertThat(stateInfo).isNotNull();
+ assertThat(stateInfo.baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+ assertThat(stateInfo.currentState).isEqualTo(DEFAULT_DEVICE_STATE);
}
@Test
- public void registerCallback_initialValueUnavailable() throws RemoteException {
+ public void registerCallback_initialValueUnavailable_nullDeviceState() throws RemoteException {
// Create a provider and a service without an initial base state.
mProvider = new TestDeviceStateProvider(null /* initialState */);
- mPolicy = new TestDeviceStatePolicy(mProvider);
+ mPolicy = new TestDeviceStatePolicy(mContext, mProvider);
setupDeviceStateManagerService();
flushHandler(); // Flush the handler to ensure the initial values are committed.
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
+ final DeviceStateInfo stateInfo = callback.getLastNotifiedInfo();
+
// The callback should never be called when the base state is not set yet.
- assertNull(callback.getLastNotifiedInfo());
+ assertThat(stateInfo).isNull();
}
@Test
public void requestState() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
- 0 /* flags */);
+ mService.getBinderService()
+ .requestState(token, OTHER_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
waitAndAssert(() -> callback.getLastNotifiedStatus(token)
== TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getOverrideState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
- assertNotNull(callback.getLastNotifiedInfo());
- assertEquals(callback.getLastNotifiedInfo().baseState, DEFAULT_DEVICE_STATE);
- assertEquals(callback.getLastNotifiedInfo().currentState, OTHER_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo()).isNotNull();
+ assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(OTHER_DEVICE_STATE);
mService.getBinderService().cancelStateRequest();
@@ -401,21 +409,20 @@
== TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
waitAndAssert(() -> mService.getCommittedState().equals(Optional.of(DEFAULT_DEVICE_STATE)));
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
- assertEquals(callback.getLastNotifiedInfo().baseState, DEFAULT_DEVICE_STATE);
- assertEquals(callback.getLastNotifiedInfo().currentState, DEFAULT_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(DEFAULT_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(DEFAULT_DEVICE_STATE);
}
@FlakyTest(bugId = 200332057)
@Test
public void requestState_pendingStateAtRequest() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
@@ -423,134 +430,129 @@
final IBinder firstRequestToken = new Binder();
final IBinder secondRequestToken = new Binder();
- assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(firstRequestToken))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(secondRequestToken))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- mService.getBinderService().requestState(firstRequestToken,
- OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+ mService.getBinderService()
+ .requestState(firstRequestToken, OTHER_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
// Flush the handler twice. The first flush ensures the request is added and the policy is
// notified, while the second flush ensures the callback is notified once the change is
// committed.
flushHandler(2 /* count */);
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
- mService.getBinderService().requestState(secondRequestToken,
- DEFAULT_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+ mService.getBinderService()
+ .requestState(secondRequestToken, DEFAULT_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
mPolicy.resumeConfigureOnce();
flushHandler();
// First request status is now canceled as there is another pending request.
- assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
- TestDeviceStateManagerCallback.STATUS_CANCELED);
+ assertThat(callback.getLastNotifiedStatus(firstRequestToken))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
// Second request status still unknown because the service is still awaiting policy
// callback.
- assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(callback.getLastNotifiedStatus(secondRequestToken))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getPendingState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
mPolicy.resumeConfigure();
flushHandler();
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
// Now cancel the second request to make the first request active.
mService.getBinderService().cancelStateRequest();
flushHandler();
- assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
- TestDeviceStateManagerCallback.STATUS_CANCELED);
- assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
- TestDeviceStateManagerCallback.STATUS_CANCELED);
+ assertThat(callback.getLastNotifiedStatus(firstRequestToken))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
+ assertThat(callback.getLastNotifiedStatus(secondRequestToken))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getPendingState()).isEmpty();
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
}
@Test
public void requestState_sameAsBaseState() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
- 0 /* flags */);
+ mService.getBinderService()
+ .requestState(token, DEFAULT_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
flushHandler();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
}
@Test
public void requestState_flagCancelWhenBaseChanges() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
+ mService.getBinderService().requestState(token, OTHER_DEVICE_STATE_IDENTIFIER,
DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES);
// Flush the handler twice. The first flush ensures the request is added and the policy is
// notified, while the second flush ensures the callback is notified once the change is
// committed.
flushHandler(2 /* count */);
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getOverrideState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE_IDENTIFIER);
flushHandler();
// Request is canceled because the base state changed.
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_CANCELED);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
}
@Test
@@ -581,8 +583,8 @@
requestState_flagCancelWhenRequesterNotOnTop_common(
// When the app is foreground, the state should not change
() -> {
- int pid = Binder.getCallingPid();
- int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
try {
mService.mProcessObserver.onForegroundActivitiesChanged(pid, uid,
true /* foregroundActivities */);
@@ -594,8 +596,8 @@
() -> {
when(mWindowProcessController.getPid()).thenReturn(FAKE_PROCESS_ID);
try {
- int pid = Binder.getCallingPid();
- int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
mService.mProcessObserver.onForegroundActivitiesChanged(pid, uid,
false /* foregroundActivities */);
@@ -609,68 +611,66 @@
@FlakyTest(bugId = 200332057)
@Test
public void requestState_becomesUnsupported() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
- mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
- 0 /* flags */);
+ mService.getBinderService()
+ .requestState(token, OTHER_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
flushHandler();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getOverrideState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
mProvider.notifySupportedDeviceStates(
new DeviceState[]{DEFAULT_DEVICE_STATE});
flushHandler();
// Request is canceled because the state is no longer supported.
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_CANCELED);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state as the override state is no longer
// supported.
- assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
}
@Test
public void requestState_unsupportedState() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
assertThrows(IllegalArgumentException.class, () -> {
final IBinder token = new Binder();
- mService.getBinderService().requestState(token,
- UNSUPPORTED_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+ mService.getBinderService()
+ .requestState(token, UNSUPPORTED_DEVICE_STATE.getIdentifier(), 0 /* flags */);
});
}
@Test
public void requestState_invalidState() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
assertThrows(IllegalArgumentException.class, () -> {
final IBinder token = new Binder();
- mService.getBinderService().requestState(token, INVALID_DEVICE_STATE_IDENTIFIER,
- 0 /* flags */);
+ mService.getBinderService()
+ .requestState(token, INVALID_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
});
}
@@ -678,40 +678,39 @@
public void requestState_beforeRegisteringCallback() {
assertThrows(IllegalStateException.class, () -> {
final IBinder token = new Binder();
- mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
- 0 /* flags */);
+ mService.getBinderService()
+ .requestState(token, DEFAULT_DEVICE_STATE_IDENTIFIER, 0 /* flags */);
});
}
@Test
public void requestBaseStateOverride() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
mService.getBinderService().requestBaseStateOverride(token,
- OTHER_DEVICE_STATE.getIdentifier(),
+ OTHER_DEVICE_STATE_IDENTIFIER,
0 /* flags */);
waitAndAssert(() -> callback.getLastNotifiedStatus(token)
== TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getOverrideBaseState().get(), OTHER_DEVICE_STATE);
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getOverrideBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
- assertNotNull(callback.getLastNotifiedInfo());
- assertEquals(callback.getLastNotifiedInfo().baseState, OTHER_DEVICE_STATE);
- assertEquals(callback.getLastNotifiedInfo().currentState, OTHER_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo()).isNotNull();
+ assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(OTHER_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(OTHER_DEVICE_STATE);
mService.getBinderService().cancelBaseStateOverride();
@@ -719,52 +718,50 @@
== TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
waitAndAssert(() -> mService.getCommittedState().equals(Optional.of(DEFAULT_DEVICE_STATE)));
- assertEquals(mSysPropSetter.getValue(),
- DEFAULT_DEVICE_STATE.getIdentifier() + ":" + DEFAULT_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertFalse(mService.getOverrideBaseState().isPresent());
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertThat(mSysPropSetter.getValue()).isEqualTo(DEFAULT_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(DEFAULT_DEVICE_STATE);
+ assertThat(mService.getOverrideBaseState()).isEmpty();
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(DEFAULT_DEVICE_STATE_IDENTIFIER);
waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
- == DEFAULT_DEVICE_STATE.getIdentifier());
- assertEquals(callback.getLastNotifiedInfo().currentState, DEFAULT_DEVICE_STATE);
+ == DEFAULT_DEVICE_STATE_IDENTIFIER);
+ assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(DEFAULT_DEVICE_STATE);
}
@Test
public void requestBaseStateOverride_cancelledByBaseStateUpdate() throws RemoteException {
- final DeviceState testDeviceState = new DeviceState(new DeviceState.Configuration.Builder(2,
- "TEST").build());
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final DeviceState testDeviceState = new DeviceState(
+ new DeviceState.Configuration.Builder(2, "TEST").build());
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
mProvider.notifySupportedDeviceStates(new DeviceState[]{DEFAULT_DEVICE_STATE,
OTHER_DEVICE_STATE, testDeviceState});
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
mService.getBinderService().requestBaseStateOverride(token,
- OTHER_DEVICE_STATE.getIdentifier(),
+ OTHER_DEVICE_STATE_IDENTIFIER,
0 /* flags */);
waitAndAssert(() -> callback.getLastNotifiedStatus(token)
== TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mSysPropSetter.getValue(),
- OTHER_DEVICE_STATE.getIdentifier() + ":" + OTHER_DEVICE_STATE.getName());
- assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE));
- assertEquals(mService.getOverrideBaseState().get(), OTHER_DEVICE_STATE);
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mSysPropSetter.getValue()).isEqualTo(OTHER_DEVICE_STATE_TRACE_STRING);
+ assertThat(mService.getBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getOverrideBaseState()).hasValue(OTHER_DEVICE_STATE);
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(OTHER_DEVICE_STATE_IDENTIFIER);
- assertNotNull(callback.getLastNotifiedInfo());
- assertEquals(callback.getLastNotifiedInfo().baseState, OTHER_DEVICE_STATE);
- assertEquals(callback.getLastNotifiedInfo().currentState, OTHER_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo()).isNotNull();
+ assertThat(callback.getLastNotifiedInfo().baseState).isEqualTo(OTHER_DEVICE_STATE);
+ assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(OTHER_DEVICE_STATE);
mProvider.setState(testDeviceState.getIdentifier());
@@ -772,22 +769,22 @@
== TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set to the new base state once the override is cleared.
waitAndAssert(() -> mService.getCommittedState().equals(Optional.of(testDeviceState)));
- assertEquals(mSysPropSetter.getValue(),
- testDeviceState.getIdentifier() + ":" + testDeviceState.getName());
- assertEquals(mService.getBaseState(), Optional.of(testDeviceState));
- assertFalse(mService.getOverrideBaseState().isPresent());
- assertFalse(mService.getOverrideState().isPresent());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- testDeviceState.getIdentifier());
+ assertThat(mSysPropSetter.getValue())
+ .isEqualTo(testDeviceState.getIdentifier() + ":" + testDeviceState.getName());
+ assertThat(mService.getBaseState()).hasValue(testDeviceState);
+ assertThat(mService.getOverrideBaseState()).isEmpty();
+ assertThat(mService.getOverrideState()).isEmpty();
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(testDeviceState.getIdentifier());
waitAndAssert(() -> callback.getLastNotifiedInfo().baseState.getIdentifier()
== testDeviceState.getIdentifier());
- assertEquals(callback.getLastNotifiedInfo().currentState, testDeviceState);
+ assertThat(callback.getLastNotifiedInfo().currentState).isEqualTo(testDeviceState);
}
@Test
public void requestBaseState_unsupportedState() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
assertThrows(IllegalArgumentException.class, () -> {
@@ -799,7 +796,7 @@
@Test
public void requestBaseState_invalidState() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
assertThrows(IllegalArgumentException.class, () -> {
@@ -814,7 +811,7 @@
assertThrows(IllegalStateException.class, () -> {
final IBinder token = new Binder();
mService.getBinderService().requestBaseStateOverride(token,
- DEFAULT_DEVICE_STATE.getIdentifier(),
+ DEFAULT_DEVICE_STATE_IDENTIFIER,
0 /* flags */);
});
}
@@ -834,21 +831,21 @@
Runnable noChangeEvent,
Runnable autoCancelEvent
) throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ final TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
flushHandler();
final IBinder token = new Binder();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_UNKNOWN);
mService.getBinderService().requestState(token,
DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP.getIdentifier(),
0 /* flags */);
flushHandler(2 /* count */);
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
assertDeviceStateConditions(
@@ -858,8 +855,8 @@
noChangeEvent.run();
flushHandler();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_ACTIVE);
assertDeviceStateConditions(
DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP,
DEFAULT_DEVICE_STATE, /* base state */
@@ -867,8 +864,8 @@
autoCancelEvent.run();
flushHandler();
- assertEquals(callback.getLastNotifiedStatus(token),
- TestDeviceStateManagerCallback.STATUS_CANCELED);
+ assertThat(callback.getLastNotifiedStatus(token))
+ .isEqualTo(TestDeviceStateManagerCallback.STATUS_CANCELED);
assertDeviceStateConditions(DEFAULT_DEVICE_STATE, DEFAULT_DEVICE_STATE,
false /* isOverrideState */);
}
@@ -881,20 +878,20 @@
* @param isOverrideState whether a state override is active.
*/
private void assertDeviceStateConditions(
- DeviceState state, DeviceState baseState,
+ @NonNull DeviceState state, @NonNull DeviceState baseState,
boolean isOverrideState) {
- assertEquals(mService.getCommittedState(), Optional.of(state));
- assertEquals(mService.getBaseState(), Optional.of(baseState));
- assertEquals(mSysPropSetter.getValue(),
- state.getIdentifier() + ":" + state.getName());
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- state.getIdentifier());
+ assertThat(mService.getCommittedState()).hasValue(state);
+ assertThat(mService.getBaseState()).hasValue(baseState);
+ assertThat(mSysPropSetter.getValue())
+ .isEqualTo(state.getIdentifier() + ":" + state.getName());
+ assertThat(mPolicy.getMostRecentRequestedStateToConfigure())
+ .isEqualTo(state.getIdentifier());
if (isOverrideState) {
// When a state override is active, the committed state should batch the override state.
- assertEquals(mService.getOverrideState().get(), state);
+ assertThat(mService.getOverrideState()).hasValue(state);
} else {
// When there is no state override, the override state should be empty.
- assertFalse(mService.getOverrideState().isPresent());
+ assertThat(mService.getOverrideState()).isEmpty();
}
}
@@ -902,10 +899,11 @@
private final DeviceStateProvider mProvider;
private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE_IDENTIFIER;
private boolean mConfigureBlocked = false;
+ @Nullable
private Runnable mPendingConfigureCompleteRunnable;
- TestDeviceStatePolicy(DeviceStateProvider provider) {
- super(InstrumentationRegistry.getContext());
+ TestDeviceStatePolicy(@NonNull Context context, @NonNull DeviceStateProvider provider) {
+ super(context);
mProvider = provider;
}
@@ -921,7 +919,7 @@
public void resumeConfigure() {
mConfigureBlocked = false;
if (mPendingConfigureCompleteRunnable != null) {
- Runnable onComplete = mPendingConfigureCompleteRunnable;
+ final Runnable onComplete = mPendingConfigureCompleteRunnable;
mPendingConfigureCompleteRunnable = null;
onComplete.run();
}
@@ -929,7 +927,7 @@
public void resumeConfigureOnce() {
if (mPendingConfigureCompleteRunnable != null) {
- Runnable onComplete = mPendingConfigureCompleteRunnable;
+ final Runnable onComplete = mPendingConfigureCompleteRunnable;
mPendingConfigureCompleteRunnable = null;
onComplete.run();
}
@@ -940,7 +938,7 @@
}
@Override
- public void configureDeviceForState(int state, Runnable onComplete) {
+ public void configureDeviceForState(int state, @NonNull Runnable onComplete) {
if (mPendingConfigureCompleteRunnable != null) {
throw new IllegalStateException("configureDeviceForState() called while configure"
+ " is pending");
@@ -966,7 +964,9 @@
OTHER_DEVICE_STATE,
DEVICE_STATE_CANCEL_WHEN_REQUESTER_NOT_ON_TOP};
- @Nullable private final DeviceState mInitialState;
+ @Nullable
+ private final DeviceState mInitialState;
+ @Nullable
private Listener mListener;
private TestDeviceStateProvider() {
@@ -991,7 +991,7 @@
}
}
- public void notifySupportedDeviceStates(DeviceState[] supportedDeviceStates) {
+ public void notifySupportedDeviceStates(@NonNull DeviceState[] supportedDeviceStates) {
mSupportedDeviceStates = supportedDeviceStates;
mListener.onSupportedDeviceStatesChanged(supportedDeviceStates,
SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
@@ -1018,17 +1018,17 @@
private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
@Override
- public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+ public void onDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
mLastNotifiedInfo = info;
}
@Override
- public void onRequestActive(IBinder token) {
+ public void onRequestActive(@NonNull IBinder token) {
mLastNotifiedStatus.put(token, STATUS_ACTIVE);
}
@Override
- public void onRequestCanceled(IBinder token) {
+ public void onRequestCanceled(@NonNull IBinder token) {
mLastNotifiedStatus.put(token, STATUS_CANCELED);
}
@@ -1041,20 +1041,22 @@
mLastNotifiedInfo = null;
}
- int getLastNotifiedStatus(IBinder requestToken) {
+ int getLastNotifiedStatus(@NonNull IBinder requestToken) {
return mLastNotifiedStatus.getOrDefault(requestToken, STATUS_UNKNOWN);
}
}
private static final class TestSystemPropertySetter implements
DeviceStateManagerService.SystemPropertySetter {
+ @NonNull
private String mValue;
@Override
- public void setDebugTracingDeviceStateProperty(String value) {
+ public void setDebugTracingDeviceStateProperty(@NonNull String value) {
mValue = value;
}
+ @NonNull
public String getValue() {
return mValue;
}
diff --git a/services/tests/servicestests/src/com/android/server/stats/pull/netstats/NetworkStatsAccumulatorTest.kt b/services/tests/servicestests/src/com/android/server/stats/pull/netstats/NetworkStatsAccumulatorTest.kt
new file mode 100644
index 0000000..8cf0e82
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/stats/pull/netstats/NetworkStatsAccumulatorTest.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2024 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.server.stats.pull.netstats
+
+import android.net.NetworkStats
+import android.net.NetworkStats.DEFAULT_NETWORK_YES
+import android.net.NetworkStats.METERED_NO
+import android.net.NetworkStats.ROAMING_NO
+import android.net.NetworkStats.SET_DEFAULT
+import android.net.NetworkStats.TAG_NONE
+import android.net.NetworkTemplate
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.testutils.assertNetworkStatsEquals
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NetworkStatsAccumulatorTest {
+
+ @Test
+ fun hasEqualParameters_differentParameters_returnsFalse() {
+ val wifiTemplate = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+ val mobileTemplate = NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE).build()
+
+ val snapshot = NetworkStatsAccumulator(wifiTemplate, false, 0, 0)
+
+ assertThat(snapshot.hasEqualParameters(mobileTemplate, false)).isFalse()
+ assertThat(snapshot.hasEqualParameters(wifiTemplate, true)).isFalse()
+ }
+
+ @Test
+ fun hasSameParameters_equalParameters_returnsTrue() {
+ val wifiTemplate1 = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+ val wifiTemplate2 = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+
+ val snapshot = NetworkStatsAccumulator(wifiTemplate1, false, 0, 0)
+
+ assertThat(snapshot.hasEqualParameters(wifiTemplate1, false)).isTrue()
+ assertThat(snapshot.hasEqualParameters(wifiTemplate2, false)).isTrue()
+ }
+
+ @Test
+ fun queryStats_lessThanOneBucketFromSnapshotEndTime_returnsAllStats() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+ // Accumulator has data until 1000 (= 0), and its end-point is still in the history period.
+ // Current time is less than one bucket away from snapshot end-point: 1050 - 1000 < 200
+ val stats = snapshot.queryStats(1050, FakeStats(500, 1050, 1))
+
+ // After the query at 1050, accumulator should have 1 * (1050 - 1000) = 50 bytes.
+ assertNetworkStatsEquals(stats, networkStatsWithBytes(50))
+ }
+
+ @Test
+ fun queryStats_oneBucketFromSnapshotEndTime_returnsCumulativeStats() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+ // Accumulator has data until 1000 (= 0), and its end-point is still in the history period.
+ // Current time is one bucket away from snapshot end-point: 1250 - 1000 > 200
+ val stats = snapshot.queryStats(1250, FakeStats(550, 1250, 2))
+
+ // After the query at 1250, accumulator should have 2 * (1250 - 1000) = 500 bytes.
+ assertNetworkStatsEquals(stats, networkStatsWithBytes(500))
+ }
+
+ @Test
+ fun queryStats_twoBucketsFromSnapshotEndTime_returnsCumulativeStats() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+ // Accumulator has data until 1000 (= 0), and its end-point is in the history period.
+ // Current time is two buckets away from snapshot end-point: 1450 - 1000 > 2*200
+ val stats = snapshot.queryStats(1450, FakeStats(600, 1450, 3))
+
+ // After the query at 1450, accumulator should have 3 * (1450 - 1000) = 1350 bytes.
+ assertNetworkStatsEquals(stats, networkStatsWithBytes(1350))
+ }
+
+ @Test
+ fun queryStats_manyBucketsFromSnapshotEndTime_returnsCumulativeStats() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+ // Accumulator has data until 1000 (= 0), and its end-point is still in the history period.
+ // Current time is many buckets away from snapshot end-point
+ val stats = snapshot.queryStats(6100, FakeStats(900, 6100, 1))
+
+ // After the query at 6100, accumulator should have 1 * (6100 - 1000) = 5100 bytes.
+ assertNetworkStatsEquals(stats, networkStatsWithBytes(5100))
+ }
+
+ @Test
+ fun queryStats_multipleQueriesAndSameHistoryWindow_returnsCumulativeStats() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+ // Accumulator is queried within the history period, whose starting point stays the same.
+ // After each query, accumulator should contain bytes from the initial end-point until now.
+ val stats1 = snapshot.queryStats(5100, FakeStats(900, 5100, 1))
+ val stats2 = snapshot.queryStats(10100, FakeStats(900, 10100, 1))
+ val stats3 = snapshot.queryStats(15100, FakeStats(900, 15100, 1))
+
+ assertNetworkStatsEquals(stats1, networkStatsWithBytes(4100))
+ assertNetworkStatsEquals(stats2, networkStatsWithBytes(9100))
+ assertNetworkStatsEquals(stats3, networkStatsWithBytes(14100))
+ }
+
+ @Test
+ fun queryStats_multipleQueriesAndSlidingHistoryWindow_returnsCumulativeStats() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1000)
+
+ // Accumulator is queried within the history period, whose starting point is moving.
+ // After each query, accumulator should contain bytes from the initial end-point until now.
+ val stats1 = snapshot.queryStats(5100, FakeStats(900, 5100, 1))
+ val stats2 = snapshot.queryStats(10100, FakeStats(4000, 10100, 1))
+ val stats3 = snapshot.queryStats(15100, FakeStats(7000, 15100, 1))
+
+ assertNetworkStatsEquals(stats1, networkStatsWithBytes(4100))
+ assertNetworkStatsEquals(stats2, networkStatsWithBytes(9100))
+ assertNetworkStatsEquals(stats3, networkStatsWithBytes(14100))
+ }
+
+ @Test
+ fun queryStats_withSnapshotEndTimeBeforeHistoryStart_addsOnlyStatsWithinHistory() {
+ val snapshot = NetworkStatsAccumulator(TEMPLATE, false, 200, 1900)
+
+ // Accumulator has data until 1000 (= 0), but its end-point is not in the history period.
+ // After the query, accumulator should add only those bytes that are covered by the history.
+ val stats = snapshot.queryStats(2700, FakeStats(2200, 2700, 1))
+
+ assertNetworkStatsEquals(stats, networkStatsWithBytes(500))
+ }
+
+ /**
+ * Simulates equally distributed traffic stats persisted over a set period of time.
+ */
+ private class FakeStats(
+ val historyStartMillis: Long, val currentTimeMillis: Long, val bytesPerMilli: Long
+ ) : NetworkStatsAccumulator.StatsQueryFunction {
+
+ override fun queryNetworkStats(
+ template: NetworkTemplate, includeTags: Boolean, startTime: Long, endTime: Long
+ ): NetworkStats {
+ val overlap = overlap(startTime, endTime, historyStartMillis, currentTimeMillis)
+ return networkStatsWithBytes(overlap * bytesPerMilli)
+ }
+ }
+
+ companion object {
+
+ private val TEMPLATE = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build()
+
+ fun networkStatsWithBytes(bytes: Long): NetworkStats {
+ val stats = NetworkStats(0, 1).addEntry(
+ NetworkStats.Entry(
+ null,
+ 0,
+ SET_DEFAULT,
+ TAG_NONE,
+ METERED_NO,
+ ROAMING_NO,
+ DEFAULT_NETWORK_YES,
+ bytes,
+ bytes / 100,
+ bytes,
+ bytes / 100,
+ 0
+ )
+ )
+ return stats
+ }
+
+ fun overlap(aStart: Long, aEnd: Long, bStart: Long, bEnd: Long): Long {
+ return maxOf(0L, minOf(aEnd, bEnd) - maxOf(aStart, bStart))
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 3bbc6b2..48bc9d7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -63,13 +63,11 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
-import android.testing.TestableLooper;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -84,7 +82,6 @@
import com.google.android.collect.Lists;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -106,7 +103,6 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-
public class ManagedServicesTest extends UiServiceTestCase {
@Mock
@@ -119,7 +115,6 @@
private ManagedServices.UserProfiles mUserProfiles;
@Mock private DevicePolicyManager mDpm;
Object mLock = new Object();
- private TestableLooper mTestableLooper;
UserInfo mZero = new UserInfo(0, "zero", 0);
UserInfo mTen = new UserInfo(10, "ten", 0);
@@ -147,7 +142,6 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mTestableLooper = new TestableLooper(Looper.getMainLooper());
mContext.setMockPackageManager(mPm);
mContext.addMockSystemService(Context.USER_SERVICE, mUm);
@@ -205,11 +199,6 @@
mIpm, APPROVAL_BY_COMPONENT);
}
- @After
- public void tearDown() throws Exception {
- mTestableLooper.destroy();
- }
-
@Test
public void testBackupAndRestore_migration() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
@@ -899,7 +888,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a", 0, true);
service.reregisterService(cn, 0);
@@ -930,7 +919,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a", 0, false);
service.reregisterService(cn, 0);
@@ -961,7 +950,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a/a", 0, true);
service.reregisterService(cn, 0);
@@ -992,7 +981,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a/a", 0, false);
service.reregisterService(cn, 0);
@@ -1064,77 +1053,6 @@
}
@Test
- public void registerService_bindingDied_rebindIsClearedOnUserSwitch() throws Exception {
- Context context = mock(Context.class);
- PackageManager pm = mock(PackageManager.class);
- ApplicationInfo ai = new ApplicationInfo();
- ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
-
- when(context.getPackageName()).thenReturn(mPkg);
- when(context.getUserId()).thenReturn(mUser.getIdentifier());
- when(context.getPackageManager()).thenReturn(pm);
- when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
-
- ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
- APPROVAL_BY_PACKAGE);
- service = spy(service);
- ComponentName cn = ComponentName.unflattenFromString("a/a");
-
- // Trigger onBindingDied for component when registering
- // => will schedule a rebind in 10 seconds
- when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- ServiceConnection sc = (ServiceConnection) args[1];
- sc.onBindingDied(cn);
- return true;
- });
- service.registerService(cn, 0);
- assertThat(service.isBound(cn, 0)).isFalse();
-
- // Switch to user 10
- service.onUserSwitched(10);
-
- // Check that the scheduled rebind for user 0 was cleared
- mTestableLooper.moveTimeForward(ManagedServices.ON_BINDING_DIED_REBIND_DELAY_MS);
- mTestableLooper.processAllMessages();
- verify(service, never()).reregisterService(any(), anyInt());
- }
-
- @Test
- public void registerService_bindingDied_rebindIsExecutedAfterTimeout() throws Exception {
- Context context = mock(Context.class);
- PackageManager pm = mock(PackageManager.class);
- ApplicationInfo ai = new ApplicationInfo();
- ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
-
- when(context.getPackageName()).thenReturn(mPkg);
- when(context.getUserId()).thenReturn(mUser.getIdentifier());
- when(context.getPackageManager()).thenReturn(pm);
- when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
-
- ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
- APPROVAL_BY_PACKAGE);
- service = spy(service);
- ComponentName cn = ComponentName.unflattenFromString("a/a");
-
- // Trigger onBindingDied for component when registering
- // => will schedule a rebind in 10 seconds
- when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- ServiceConnection sc = (ServiceConnection) args[1];
- sc.onBindingDied(cn);
- return true;
- });
- service.registerService(cn, 0);
- assertThat(service.isBound(cn, 0)).isFalse();
-
- // Check that the scheduled rebind is run
- mTestableLooper.moveTimeForward(ManagedServices.ON_BINDING_DIED_REBIND_DELAY_MS);
- mTestableLooper.processAllMessages();
- verify(service, times(1)).reregisterService(eq(cn), eq(0));
- }
-
- @Test
public void testPackageUninstall_packageNoLongerInApprovedList() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -1293,64 +1211,6 @@
}
@Test
- public void testUpgradeAppNoIntentFilterNoRebind() throws Exception {
- Context context = spy(getContext());
- doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
-
- ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
- mIpm, APPROVAL_BY_COMPONENT);
-
- List<String> packages = new ArrayList<>();
- packages.add("package");
- addExpectedServices(service, packages, 0);
-
- final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
- final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
-
- // Both components are approved initially
- mExpectedPrimaryComponentNames.clear();
- mExpectedPrimaryPackages.clear();
- mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
- mExpectedSecondaryComponentNames.clear();
- mExpectedSecondaryPackages.clear();
-
- loadXml(service);
-
- //Component package/C1 loses serviceInterface intent filter
- ManagedServices.Config config = service.getConfig();
- when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt()))
- .thenAnswer(new Answer<List<ResolveInfo>>() {
- @Override
- public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
- throws Throwable {
- Object[] args = invocationOnMock.getArguments();
- Intent invocationIntent = (Intent) args[0];
- if (invocationIntent != null) {
- if (invocationIntent.getAction().equals(config.serviceInterface)
- && packages.contains(invocationIntent.getPackage())) {
- List<ResolveInfo> dummyServices = new ArrayList<>();
- ResolveInfo resolveInfo = new ResolveInfo();
- ServiceInfo serviceInfo = new ServiceInfo();
- serviceInfo.packageName = invocationIntent.getPackage();
- serviceInfo.name = approvedComponent.getClassName();
- serviceInfo.permission = service.getConfig().bindPermission;
- resolveInfo.serviceInfo = serviceInfo;
- dummyServices.add(resolveInfo);
- return dummyServices;
- }
- }
- return new ArrayList<>();
- }
- });
-
- // Trigger package update
- service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
-
- assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
- assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
- }
-
- @Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -1363,21 +1223,6 @@
"user10package1/K", "user10.3/Component", "user10package2/L",
"user10.4/Component"}));
- // mock permissions for services
- PackageManager pm = mock(PackageManager.class);
- when(getContext().getPackageManager()).thenReturn(pm);
- List<ComponentName> enabledComponents = List.of(
- ComponentName.unflattenFromString("package/Comp"),
- ComponentName.unflattenFromString("package/C2"),
- ComponentName.unflattenFromString("again/M4"),
- ComponentName.unflattenFromString("user10package/B"),
- ComponentName.unflattenFromString("user10/Component"),
- ComponentName.unflattenFromString("user10package1/K"),
- ComponentName.unflattenFromString("user10.3/Component"),
- ComponentName.unflattenFromString("user10package2/L"),
- ComponentName.unflattenFromString("user10.4/Component"));
- mockServiceInfoWithMetaData(enabledComponents, service, pm, new ArrayMap<>());
-
for (int userId : expectedEnabled.keySet()) {
ArrayList<String> expectedForUser = expectedEnabled.get(userId);
for (int i = 0; i < expectedForUser.size(); i++) {
@@ -2099,7 +1944,7 @@
metaDataAutobindAllow.putBoolean(META_DATA_DEFAULT_AUTOBIND, true);
metaDatas.put(cn_allowed, metaDataAutobindAllow);
- mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);
+ mockServiceInfoWithMetaData(componentNames, service, metaDatas);
service.addApprovedList(cn_allowed.flattenToString(), 0, true);
service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -2144,7 +1989,7 @@
metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false);
metaDatas.put(cn_disallowed, metaDataAutobindDisallow);
- mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);
+ mockServiceInfoWithMetaData(componentNames, service, metaDatas);
service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -2183,7 +2028,7 @@
metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false);
metaDatas.put(cn_disallowed, metaDataAutobindDisallow);
- mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);
+ mockServiceInfoWithMetaData(componentNames, service, metaDatas);
service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -2254,8 +2099,8 @@
}
private void mockServiceInfoWithMetaData(List<ComponentName> componentNames,
- ManagedServices service, PackageManager packageManager,
- ArrayMap<ComponentName, Bundle> metaDatas) throws RemoteException {
+ ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas)
+ throws RemoteException {
when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
(Answer<ServiceInfo>) invocation -> {
ComponentName invocationCn = invocation.getArgument(0);
@@ -2270,39 +2115,6 @@
return null;
}
);
-
- // add components to queryIntentServicesAsUser response
- final List<String> packages = new ArrayList<>();
- for (ComponentName cn: componentNames) {
- packages.add(cn.getPackageName());
- }
- ManagedServices.Config config = service.getConfig();
- when(packageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt())).
- thenAnswer(new Answer<List<ResolveInfo>>() {
- @Override
- public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
- throws Throwable {
- Object[] args = invocationOnMock.getArguments();
- Intent invocationIntent = (Intent) args[0];
- if (invocationIntent != null) {
- if (invocationIntent.getAction().equals(config.serviceInterface)
- && packages.contains(invocationIntent.getPackage())) {
- List<ResolveInfo> dummyServices = new ArrayList<>();
- for (ComponentName cn: componentNames) {
- ResolveInfo resolveInfo = new ResolveInfo();
- ServiceInfo serviceInfo = new ServiceInfo();
- serviceInfo.packageName = invocationIntent.getPackage();
- serviceInfo.name = cn.getClassName();
- serviceInfo.permission = service.getConfig().bindPermission;
- resolveInfo.serviceInfo = serviceInfo;
- dummyServices.add(resolveInfo);
- }
- return dummyServices;
- }
- }
- return new ArrayList<>();
- }
- });
}
private void resetComponentsAndPackages() {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 7e4ae67..797b95b5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -25,7 +25,6 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNull;
-
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
@@ -194,8 +193,6 @@
public void testWriteXml_userTurnedOffNAS() throws Exception {
int userId = ActivityManager.getCurrentUser();
- doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
-
mAssistants.loadDefaultsFromConfig(true);
mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
@@ -401,10 +398,6 @@
public void testSetPackageOrComponentEnabled_onlyOnePackage() throws Exception {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
ComponentName component2 = ComponentName.unflattenFromString("package/Component2");
-
- doReturn(true).when(mAssistants).isValidService(eq(component1), eq(mZero.id));
- doReturn(true).when(mAssistants).isValidService(eq(component2), eq(mZero.id));
-
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
true, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
@@ -550,7 +543,6 @@
public void testSetAdjustmentTypeSupportedState() throws Exception {
int userId = ActivityManager.getCurrentUser();
- doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
mAssistants.loadDefaultsFromConfig(true);
mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
true, true);
@@ -574,7 +566,6 @@
public void testSetAdjustmentTypeSupportedState_readWriteXml_entries() throws Exception {
int userId = ActivityManager.getCurrentUser();
- doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
mAssistants.loadDefaultsFromConfig(true);
mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
true, true);
@@ -598,7 +589,6 @@
public void testSetAdjustmentTypeSupportedState_readWriteXml_empty() throws Exception {
int userId = ActivityManager.getCurrentUser();
- doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
mAssistants.loadDefaultsFromConfig(true);
mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
true, true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
index d8373c5..50c2c2f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatUtilsTest.java
@@ -18,16 +18,26 @@
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
import android.app.TaskInfo;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.Surface;
import androidx.annotation.NonNull;
+import com.android.window.flags.Flags;
+
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -174,9 +184,13 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
public void getTaskInfoPropagatesCameraCompatMode() {
runTestScenario((robot) -> {
- robot.applyOnActivity(AppCompatActivityRobot::createActivityWithComponentInNewTask);
+ robot.dw().allowEnterDesktopMode(/* isAllowed= */ true);
+ robot.applyOnActivity(
+ AppCompatActivityRobot::createActivityWithComponentInNewTaskAndDisplay);
+ robot.setCameraCompatTreatmentEnabledForActivity(/* enabled= */ true);
robot.setFreeformCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
robot.checkTaskInfoFreeformCameraCompatMode(
@@ -212,6 +226,15 @@
spyOn(activity.mAppCompatController.getAppCompatAspectRatioPolicy());
}
+ @Override
+ void onPostDisplayContentCreation(@NonNull DisplayContent displayContent) {
+ super.onPostDisplayContentCreation(displayContent);
+ mockPortraitDisplay(displayContent);
+ if (displayContent.mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy()) {
+ spyOn(displayContent.mAppCompatCameraPolicy.mCameraCompatFreeformPolicy);
+ }
+ }
+
void transparentActivity(@NonNull Consumer<AppCompatTransparentActivityRobot> consumer) {
// We always create at least an opaque activity in a Task.
activity().createNewTaskWithBaseActivity();
@@ -235,8 +258,8 @@
}
void setFreeformCameraCompatMode(@FreeformCameraCompatMode int mode) {
- activity().top().mAppCompatController.getAppCompatCameraOverrides()
- .setFreeformCameraCompatMode(mode);
+ doReturn(mode).when(activity().top().mDisplayContent.mAppCompatCameraPolicy
+ .mCameraCompatFreeformPolicy).getCameraCompatMode(activity().top());
}
void checkTopActivityLetterboxReason(@NonNull String expected) {
@@ -258,6 +281,24 @@
Assert.assertEquals(mode, getTopTaskInfo().appCompatTaskInfo
.cameraCompatTaskInfo.freeformCameraCompatMode);
}
- }
+ void setCameraCompatTreatmentEnabledForActivity(boolean enabled) {
+ doReturn(enabled).when(activity().displayContent().mAppCompatCameraPolicy
+ .mCameraCompatFreeformPolicy).isTreatmentEnabledForActivity(
+ eq(activity().top()), anyBoolean());
+ }
+
+ private void mockPortraitDisplay(DisplayContent displayContent) {
+ doAnswer(invocation -> {
+ DisplayInfo displayInfo = new DisplayInfo();
+ displayContent.getDisplay().getDisplayInfo(displayInfo);
+ displayInfo.rotation = Surface.ROTATION_90;
+ // Set height and width so that the natural orientation (when rotation is 0) is
+ // portrait.
+ displayInfo.logicalHeight = 600;
+ displayInfo.logicalWidth = 800;
+ return displayInfo;
+ }).when(displayContent.mWmService.mDisplayManagerInternal).getDisplayInfo(anyInt());
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index a8ccf95..a07fd23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -223,10 +223,13 @@
setDisplayRotation(Surface.ROTATION_270);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
- callOnActivityConfigurationChanging(mActivity);
+ callOnActivityConfigurationChanging(mActivity, /* letterboxNew= */ true,
+ /* lastLetterbox= */ false);
mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
- callOnActivityConfigurationChanging(mActivity);
+ // Activity is letterboxed from the previous configuration change.
+ callOnActivityConfigurationChanging(mActivity, /* letterboxNew= */ true,
+ /* lastLetterbox= */ true);
assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
assertActivityRefreshRequested(/* refreshRequested */ true);
@@ -264,6 +267,48 @@
@Test
@EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ public void testShouldRefreshActivity_appBoundsChanged_returnsTrue() {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ Configuration oldConfiguration = createConfiguration(/* letterbox= */ false);
+ Configuration newConfiguration = createConfiguration(/* letterbox= */ true);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertTrue(mCameraCompatFreeformPolicy.shouldRefreshActivity(mActivity, newConfiguration,
+ oldConfiguration));
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ public void testShouldRefreshActivity_displayRotationChanged_returnsTrue() {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
+ Configuration newConfiguration = createConfiguration(/* letterbox= */ true);
+
+ oldConfiguration.windowConfiguration.setDisplayRotation(0);
+ newConfiguration.windowConfiguration.setDisplayRotation(90);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertTrue(mCameraCompatFreeformPolicy.shouldRefreshActivity(mActivity, newConfiguration,
+ oldConfiguration));
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+ public void testShouldRefreshActivity_appBoundsNorDisplayChanged_returnsFalse() {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
+ Configuration newConfiguration = createConfiguration(/* letterbox= */ true);
+
+ oldConfiguration.windowConfiguration.setDisplayRotation(0);
+ newConfiguration.windowConfiguration.setDisplayRotation(0);
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertFalse(mCameraCompatFreeformPolicy.shouldRefreshActivity(mActivity, newConfiguration,
+ oldConfiguration));
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
public void testOnActivityConfigurationChanging_refreshDisabledViaFlag_noRefresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -306,6 +351,7 @@
}
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
public void testGetCameraCompatAspectRatio_activityNotInCameraCompat_returnsDefaultAspRatio() {
configureActivity(SCREEN_ORIENTATION_FULL_USER);
@@ -318,6 +364,7 @@
}
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
public void testGetCameraCompatAspectRatio_activityInCameraCompat_returnsConfigAspectRatio() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
final float configAspectRatio = 1.5f;
@@ -331,8 +378,8 @@
/* delta= */ 0.001);
}
-
@Test
+ @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
public void testGetCameraCompatAspectRatio_inCameraCompatPerAppOverride_returnDefAspectRatio() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
final float configAspectRatio = 1.5f;
@@ -411,9 +458,15 @@
}
private void callOnActivityConfigurationChanging(ActivityRecord activity) {
+ callOnActivityConfigurationChanging(activity, /* letterboxNew= */ true,
+ /* lastLetterbox= */false);
+ }
+
+ private void callOnActivityConfigurationChanging(ActivityRecord activity, boolean letterboxNew,
+ boolean lastLetterbox) {
mActivityRefresher.onActivityConfigurationChanging(activity,
- /* newConfig */ createConfiguration(/*letterbox=*/ true),
- /* lastReportedConfig */ createConfiguration(/*letterbox=*/ false));
+ /* newConfig */ createConfiguration(letterboxNew),
+ /* lastReportedConfig */ createConfiguration(lastLetterbox));
}
private Configuration createConfiguration(boolean letterbox) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 6111a65..8bbba1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -94,6 +94,7 @@
import android.view.ContentRecordingSession;
import android.view.IWindow;
import android.view.InputChannel;
+import android.view.InputDevice;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
@@ -1275,6 +1276,48 @@
}
@Test
+ public void testInputDeviceNotifyConfigurationChanged() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_FILTER_IRRELEVANT_INPUT_DEVICE_CHANGE);
+ spyOn(mDisplayContent);
+ doReturn(false).when(mDisplayContent).sendNewConfiguration();
+ final InputDevice deviceA = mock(InputDevice.class);
+ final InputDevice deviceB = mock(InputDevice.class);
+ doReturn("deviceA").when(deviceA).getDescriptor();
+ doReturn("deviceB").when(deviceB).getDescriptor();
+ final InputDevice[] devices1 = { deviceA };
+ final InputDevice[] devices2 = { deviceB, deviceA };
+ final Runnable verifySendNewConfiguration = () -> {
+ clearInvocations(mDisplayContent);
+ mWm.mInputManagerCallback.notifyConfigurationChanged();
+ verify(mDisplayContent).sendNewConfiguration();
+ };
+ doReturn(devices1).when(mWm.mInputManager).getInputDevices();
+ verifySendNewConfiguration.run();
+
+ doReturn(devices2).when(mWm.mInputManager).getInputDevices();
+ verifySendNewConfiguration.run();
+
+ doReturn(true).when(deviceB).isEnabled();
+ verifySendNewConfiguration.run();
+
+ doReturn(true).when(deviceA).isExternal();
+ verifySendNewConfiguration.run();
+
+ doReturn(1).when(deviceA).getSources();
+ verifySendNewConfiguration.run();
+
+ doReturn(1).when(deviceA).getAssociatedDisplayId();
+ verifySendNewConfiguration.run();
+
+ doReturn(1).when(deviceA).getKeyboardType();
+ verifySendNewConfiguration.run();
+
+ clearInvocations(mDisplayContent);
+ mWm.mInputManagerCallback.notifyConfigurationChanged();
+ verify(mDisplayContent, never()).sendNewConfiguration();
+ }
+
+ @Test
public void testReportSystemGestureExclusionChanged_invalidWindow() {
final Session session = mock(Session.class);
final IWindow window = mock(IWindow.class);
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 27e9ffa..1e997b3 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -47,7 +47,6 @@
java_library {
name: "wm-flicker-common-assertions",
- platform_apis: true,
optimize: {
enabled: false,
},
diff --git a/tests/FlickerTests/test-apps/app-helpers/Android.bp b/tests/FlickerTests/test-apps/app-helpers/Android.bp
index fc4d71c..e8bb64a 100644
--- a/tests/FlickerTests/test-apps/app-helpers/Android.bp
+++ b/tests/FlickerTests/test-apps/app-helpers/Android.bp
@@ -25,7 +25,6 @@
java_library {
name: "wm-flicker-common-app-helpers",
- platform_apis: true,
optimize: {
enabled: false,
},
diff --git a/tests/graphics/SilkFX/res/layout/view_blur_behind.xml b/tests/graphics/SilkFX/res/layout/view_blur_behind.xml
new file mode 100644
index 0000000..83b1fa4
--- /dev/null
+++ b/tests/graphics/SilkFX/res/layout/view_blur_behind.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="I'm a little teapot" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="Something. Something." />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="wowwowwowwowwowwowwowwowwowwowwowwowwowwowwow" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="I'm a little teapot" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="Something. Something." />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="/\\/\\/\\/\\/\\/\\/\\/\\/\\/" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:textSize="24dp"
+ android:text="^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^" />
+
+ </LinearLayout>
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="300dp" />
+
+ <com.android.test.silkfx.materials.BlurBehindContainer
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="#33AAAAAA"
+ android:padding="32dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="48dp"
+ android:text="Blur!" />
+
+ </com.android.test.silkfx.materials.BlurBehindContainer>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1024dp" />
+
+ </LinearLayout>
+
+ </ScrollView>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
index 59a6078..6b6d3b8 100644
--- a/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -61,7 +61,8 @@
)),
DemoGroup("Materials", listOf(
Demo("Glass", GlassActivity::class),
- Demo("Background Blur", BackgroundBlurActivity::class)
+ Demo("Background Blur", BackgroundBlurActivity::class),
+ Demo("View blur behind", R.layout.view_blur_behind, commonControls = false)
))
)
diff --git a/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BlurBehindContainer.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BlurBehindContainer.kt
new file mode 100644
index 0000000..ce6348e
--- /dev/null
+++ b/tests/graphics/SilkFX/src/com/android/test/silkfx/materials/BlurBehindContainer.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.test.silkfx.materials
+
+import android.content.Context
+import android.graphics.RenderEffect
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.widget.FrameLayout
+
+class BlurBehindContainer(context: Context, attributeSet: AttributeSet) : FrameLayout(context, attributeSet) {
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ setBackdropRenderEffect(
+ RenderEffect.createBlurEffect(16.0f, 16.0f, Shader.TileMode.CLAMP))
+ }
+}
\ No newline at end of file
diff --git a/wifi/java/src/android/net/wifi/WifiMigration.java b/wifi/java/src/android/net/wifi/WifiMigration.java
index f1850dd..28e9c45 100644
--- a/wifi/java/src/android/net/wifi/WifiMigration.java
+++ b/wifi/java/src/android/net/wifi/WifiMigration.java
@@ -38,6 +38,8 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.os.BackgroundThread;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
@@ -48,6 +50,8 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.IntConsumer;
/**
* Class used to provide one time hooks for existing OEM devices to migrate their config store
@@ -605,13 +609,35 @@
/**
* Migrate any certificates in Legacy Keystore to the newer WifiBlobstore database.
*
- * If there are no certificates to migrate, this method will return immediately.
+ * Operation will be handled on the BackgroundThread, and the result will be posted
+ * to the provided Executor.
+ *
+ * @param executor The executor on which callback will be invoked
+ * @param resultsCallback Callback to receive the status code
*
* @hide
*/
@FlaggedApi(Flags.FLAG_LEGACY_KEYSTORE_TO_WIFI_BLOBSTORE_MIGRATION_READ_ONLY)
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static @KeystoreMigrationStatus int migrateLegacyKeystoreToWifiBlobstore() {
+ public static void migrateLegacyKeystoreToWifiBlobstore(
+ @NonNull Executor executor, @NonNull IntConsumer resultsCallback) {
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
+ BackgroundThread.getHandler().post(() -> {
+ int status = migrateLegacyKeystoreToWifiBlobstoreInternal();
+ executor.execute(() -> {
+ resultsCallback.accept(status);
+ });
+ });
+ }
+
+ /**
+ * Synchronously perform the Keystore migration described in
+ * {@link #migrateLegacyKeystoreToWifiBlobstore(Executor, IntConsumer)}
+ *
+ * @hide
+ */
+ public static @KeystoreMigrationStatus int migrateLegacyKeystoreToWifiBlobstoreInternal() {
if (!WifiBlobStore.supplicantCanAccessBlobstore()) {
// Supplicant cannot access WifiBlobstore, so keep the certs in Legacy Keystore
Log.i(TAG, "Avoiding migration since supplicant cannot access WifiBlobstore");
diff --git a/wifi/tests/src/android/net/wifi/WifiMigrationTest.java b/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
index 0aa299f..ce5b60a 100644
--- a/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
@@ -81,7 +81,7 @@
public void testKeystoreMigrationAvoidedOnLegacyVendorPartition() {
when(WifiBlobStore.supplicantCanAccessBlobstore()).thenReturn(false);
assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
verifyNoMoreInteractions(mLegacyKeystore, mWifiBlobStore);
}
@@ -93,7 +93,7 @@
public void testKeystoreMigrationNoLegacyAliases() throws Exception {
when(mLegacyKeystore.list(anyString(), anyInt())).thenReturn(new String[0]);
assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
verify(mLegacyKeystore).list(anyString(), anyInt());
verifyNoMoreInteractions(mLegacyKeystore, mWifiBlobStore);
}
@@ -110,7 +110,7 @@
when(mWifiBlobStore.list(anyString())).thenReturn(blobstoreAliases);
assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
verify(mWifiBlobStore, times(legacyAliases.length)).put(anyString(), any(byte[].class));
}
@@ -129,7 +129,7 @@
// Expect that only the unique legacy alias is migrated to the blobstore
assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
verify(mWifiBlobStore).list(anyString());
verify(mWifiBlobStore).put(eq(uniqueLegacyAlias), any(byte[].class));
verifyNoMoreInteractions(mWifiBlobStore);
@@ -146,7 +146,7 @@
when(mLegacyKeystore.list(anyString(), anyInt())).thenThrow(
new ServiceSpecificException(ILegacyKeystore.ERROR_SYSTEM_ERROR));
assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
}
/**
@@ -157,6 +157,6 @@
public void testKeystoreMigrationFailsIfExceptionEncountered() throws Exception {
when(mLegacyKeystore.list(anyString(), anyInt())).thenThrow(new RemoteException());
assertEquals(WifiMigration.KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION,
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstoreInternal());
}
}