diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 45588e831cb9..84d05c8b4144 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -2918,6 +2918,13 @@ public class DeviceIdleController extends SystemService reasonCode, reason).sendToTarget(); } reportTempWhitelistChangedLocked(uid, true); + } else { + // The uid is already temp allowlisted, only need to update AMS for temp allowlist + // duration. + if (mLocalActivityManager != null) { + mLocalActivityManager.updateDeviceIdleTempAllowlist(null, uid, true, + duration, tempAllowListType, reasonCode, reason, callingUid); + } } } if (informWhitelistChanged) { @@ -3941,6 +3948,10 @@ public class DeviceIdleController extends SystemService if (idleUntil) { mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); + } else if (mState == STATE_LOCATING) { + // Use setExact so we don't keep the GPS active for too long. + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } else { if (mConstants.USE_WINDOW_ALARMS) { mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp index b2b66c27f795..3534624a58a2 100644 --- a/cmds/bootanimation/Android.bp +++ b/cmds/bootanimation/Android.bp @@ -71,7 +71,7 @@ cc_library_shared { "libui", "libjnigraphics", "libEGL", - "libGLESv1_CM", + "libGLESv2", "libgui", ], } diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 3109c5c1e075..6c8cab7783b6 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -52,9 +52,8 @@ #include #include #include - -#include -#include +#include +#include #include #include "BootAnimation.h" @@ -108,6 +107,93 @@ static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress"; static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays"; static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1; static constexpr size_t TEXT_POS_LEN_MAX = 16; +static const int DYNAMIC_COLOR_COUNT = 4; +static const char U_TEXTURE[] = "uTexture"; +static const char U_FADE[] = "uFade"; +static const char U_CROP_AREA[] = "uCropArea"; +static const char U_START_COLOR_PREFIX[] = "uStartColor"; +static const char U_END_COLOR_PREFIX[] = "uEndColor"; +static const char U_COLOR_PROGRESS[] = "uColorProgress"; +static const char A_UV[] = "aUv"; +static const char A_POSITION[] = "aPosition"; +static const char VERTEX_SHADER_SOURCE[] = R"( + precision mediump float; + attribute vec4 aPosition; + attribute highp vec2 aUv; + varying highp vec2 vUv; + void main() { + gl_Position = aPosition; + vUv = aUv; + })"; +static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"( + precision mediump float; + const float cWhiteMaskThreshold = 0.05; + uniform sampler2D uTexture; + uniform float uFade; + uniform float uColorProgress; + uniform vec4 uStartColor0; + uniform vec4 uStartColor1; + uniform vec4 uStartColor2; + uniform vec4 uStartColor3; + uniform vec4 uEndColor0; + uniform vec4 uEndColor1; + uniform vec4 uEndColor2; + uniform vec4 uEndColor3; + varying highp vec2 vUv; + void main() { + vec4 mask = texture2D(uTexture, vUv); + float r = mask.r; + float g = mask.g; + float b = mask.b; + float a = mask.a; + // If all channels have values, render pixel as a shade of white. + float useWhiteMask = step(cWhiteMaskThreshold, r) + * step(cWhiteMaskThreshold, g) + * step(cWhiteMaskThreshold, b) + * step(cWhiteMaskThreshold, a); + vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress) + + g * mix(uStartColor1, uEndColor1, uColorProgress) + + b * mix(uStartColor2, uEndColor2, uColorProgress) + + a * mix(uStartColor3, uEndColor3, uColorProgress); + color = mix(color, vec4(vec3((r + g + b + a) * 0.25), 1.0), useWhiteMask); + gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a; + })"; +static const char IMAGE_FRAG_SHADER_SOURCE[] = R"( + precision mediump float; + uniform sampler2D uTexture; + uniform float uFade; + varying highp vec2 vUv; + void main() { + vec4 color = texture2D(uTexture, vUv); + gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a; + })"; +static const char TEXT_FRAG_SHADER_SOURCE[] = R"( + precision mediump float; + uniform sampler2D uTexture; + uniform vec4 uCropArea; + varying highp vec2 vUv; + void main() { + vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x), + mix(uCropArea.y, uCropArea.w, vUv.y)); + gl_FragColor = texture2D(uTexture, uv); + })"; + +static GLfloat quadPositions[] = { + -0.5f, -0.5f, + +0.5f, -0.5f, + +0.5f, +0.5f, + +0.5f, +0.5f, + -0.5f, +0.5f, + -0.5f, -0.5f +}; +static GLfloat quadUVs[] = { + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 0.0f, + 0.0f, 1.0f +}; // --------------------------------------------------------------------------- @@ -163,7 +249,8 @@ void BootAnimation::binderDied(const wp&) { requestExit(); } -static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) { +static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo, + bool premultiplyAlpha) { AImageDecoder* decoder = nullptr; AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder); if (!decoder) { @@ -177,6 +264,10 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm outInfo->stride = AImageDecoder_getMinimumStride(decoder); outInfo->flags = 0; + if (!premultiplyAlpha) { + AImageDecoder_setUnpremultipliedRequired(decoder, true); + } + const size_t size = outInfo->stride * outInfo->height; void* pixels = malloc(size); int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size); @@ -190,13 +281,14 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm } status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, - const char* name) { + const char* name, bool premultiplyAlpha) { Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); if (asset == nullptr) return NO_INIT; AndroidBitmapInfo bitmapInfo; - void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo); + void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo, + premultiplyAlpha); auto pixelDeleter = std::unique_ptr{ pixels, free }; asset->close(); @@ -209,7 +301,6 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, const int w = bitmapInfo.width; const int h = bitmapInfo.height; - GLint crop[4] = { 0, h, w, -h }; texture->w = w; texture->h = h; @@ -237,18 +328,19 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, break; } - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return NO_ERROR; } -status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { +status_t BootAnimation::initTexture(FileMap* map, int* width, int* height, + bool premultiplyAlpha) { AndroidBitmapInfo bitmapInfo; - void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo); + void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo, + premultiplyAlpha); auto pixelDeleter = std::unique_ptr{ pixels, free }; // FileMap memory is never released until application exit. @@ -263,7 +355,6 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { const int w = bitmapInfo.width; const int h = bitmapInfo.height; - GLint crop[4] = { 0, h, w, -h }; int tw = 1 << (31 - __builtin_clz(w)); int th = 1 << (31 - __builtin_clz(h)); if (tw < w) tw <<= 1; @@ -297,7 +388,10 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { break; } - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); *width = w; *height = h; @@ -470,7 +564,9 @@ status_t BootAnimation::readyToRun() { eglInitialize(display, nullptr, nullptr); EGLConfig config = getEglConfig(display); EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr); - EGLContext context = eglCreateContext(display, config, nullptr, 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); @@ -503,11 +599,6 @@ status_t BootAnimation::readyToRun() { void BootAnimation::projectSceneToWindow() { glViewport(0, 0, mWidth, mHeight); glScissor(0, 0, mWidth, mHeight); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrthof(0, static_cast(mWidth), 0, static_cast(mHeight), -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); } void BootAnimation::resizeSurface(int newWidth, int newHeight) { @@ -600,8 +691,76 @@ void BootAnimation::findBootAnimationFile() { } } +GLuint compileShader(GLenum shaderType, const GLchar *source) { + GLuint shader = glCreateShader(shaderType); + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) { + SLOGE("Compile shader failed. Shader type: %d", shaderType); + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + std::vector errorLog(maxLength); + glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + SLOGE("Shader compilation error: %s", &errorLog[0]); + return 0; + } + return shader; +} + +GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) { + GLuint program = glCreateProgram(); + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked); + if (isLinked == GL_FALSE) { + SLOGE("Linking shader failed. Shader handles: vert %d, frag %d", + vertexShader, fragmentShader); + return 0; + } + return program; +} + +void BootAnimation::initShaders() { + bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled; + GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE); + GLuint imageFragmentShader = + compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled + ? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE + : (const GLchar *)IMAGE_FRAG_SHADER_SOURCE); + GLuint textFragmentShader = + compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE); + + // Initialize image shader. + mImageShader = linkShader(vertexShader, imageFragmentShader); + GLint positionLocation = glGetAttribLocation(mImageShader, A_POSITION); + GLint uvLocation = glGetAttribLocation(mImageShader, A_UV); + mImageTextureLocation = glGetUniformLocation(mImageShader, U_TEXTURE); + mImageFadeLocation = glGetUniformLocation(mImageShader, U_FADE); + glEnableVertexAttribArray(positionLocation); + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions); + glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs); + glEnableVertexAttribArray(uvLocation); + + // Initialize text shader. + mTextShader = linkShader(vertexShader, textFragmentShader); + positionLocation = glGetAttribLocation(mTextShader, A_POSITION); + uvLocation = glGetAttribLocation(mTextShader, A_UV); + mTextTextureLocation = glGetUniformLocation(mTextShader, U_TEXTURE); + mTextCropAreaLocation = glGetUniformLocation(mTextShader, U_CROP_AREA); + glEnableVertexAttribArray(positionLocation); + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions); + glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs); + glEnableVertexAttribArray(uvLocation); +} + bool BootAnimation::threadLoop() { bool result; + initShaders(); + // We have no bootanimation file, so we use the stock android logo // animation. if (mZipFileName.isEmpty()) { @@ -623,6 +782,8 @@ bool BootAnimation::threadLoop() { } bool BootAnimation::android() { + glActiveTexture(GL_TEXTURE0); + SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); @@ -631,19 +792,16 @@ bool BootAnimation::android() { mCallbacks->init({}); // clear screen - glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); + glUseProgram(mImageShader); + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mDisplay, mSurface); - glEnable(GL_TEXTURE_2D); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - // Blend state glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); const nsecs_t startTime = systemTime(); do { @@ -666,12 +824,12 @@ bool BootAnimation::android() { glEnable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); - glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h); - glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h); + drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h); + drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h); glEnable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[0].name); - glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h); + drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h); EGLBoolean res = eglSwapBuffers(mDisplay, mSurface); if (res == EGL_FALSE) @@ -766,6 +924,20 @@ static bool parseColor(const char str[7], float color[3]) { return true; } +// Parse a color represented as a signed decimal int string. +// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6). +// If the input color string is empty, set color with values in defaultColor. +static void parseColorDecimalString(const std::string& colorString, + float color[3], float defaultColor[3]) { + if (colorString == "") { + memcpy(color, defaultColor, sizeof(float) * 3); + return; + } + int colorInt = atoi(colorString.c_str()); + color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r + color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g + color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b +} static bool readFile(ZipFileRO* zip, const char* name, String8& outString) { ZipEntryRO entry = zip->findEntryByName(name); @@ -798,10 +970,10 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) { status = initTexture(font->map, &font->texture.w, &font->texture.h); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else if (fallback != nullptr) { status = initTexture(&font->texture, mAssets, fallback); } else { @@ -816,40 +988,11 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) { return status; } -void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth, - const int frameHeight, const Animation::Part& part, - const int fadedFramesCount) { - glEnable(GL_BLEND); - glEnableClientState(GL_VERTEX_ARRAY); - glDisable(GL_TEXTURE_2D); - // avoid creating a hole due to mixing result alpha with GL_REPLACE texture - glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - - const float alpha = static_cast(fadedFramesCount) / part.framesToFadeCount; - glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha); - - const float frameStartX = static_cast(frameLeft); - const float frameStartY = static_cast(frameBottom); - const float frameEndX = frameStartX + frameWidth; - const float frameEndY = frameStartY + frameHeight; - const GLfloat frameRect[] = { - frameStartX, frameStartY, - frameEndX, frameStartY, - frameEndX, frameEndY, - frameStartX, frameEndY - }; - glVertexPointer(2, GL_FLOAT, 0, frameRect); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_TEXTURE_2D); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_BLEND); -} - void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) { glEnable(GL_BLEND); // Allow us to draw on top of the animation glBindTexture(GL_TEXTURE_2D, font.texture.name); + glUseProgram(mTextShader); + glUniform1i(mTextTextureLocation, 0); const int len = strlen(str); const int strWidth = font.char_width * len; @@ -865,8 +1008,6 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* *y = mHeight + *y - font.char_height; } - int cropRect[4] = { 0, 0, font.char_width, -font.char_height }; - for (int i = 0; i < len; i++) { char c = str[i]; @@ -878,13 +1019,13 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters const int row = charPos / FONT_NUM_COLS; const int col = charPos % FONT_NUM_COLS; - cropRect[0] = col * font.char_width; // Left of column - cropRect[1] = row * font.char_height * 2; // Top of row - // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line - cropRect[1] += bold ? 2 * font.char_height : font.char_height; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); - - glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height); + // Bold fonts are expected in the second half of each row. + float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS; + float u0 = ((float)col) / FONT_NUM_COLS; + 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); *x += font.char_width; } @@ -938,6 +1079,8 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { return false; } char const* s = desString.string(); + std::string dynamicColoringPartName = ""; + bool postDynamicColoring = false; // Parse the description file for (;;) { @@ -952,11 +1095,19 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { int pause = 0; int progress = 0; int framesToFadeCount = 0; + int colorTransitionStart = 0; + int colorTransitionEnd = 0; char path[ANIM_ENTRY_NAME_MAX]; char color[7] = "000000"; // default to black if unspecified char clockPos1[TEXT_POS_LEN_MAX + 1] = ""; char clockPos2[TEXT_POS_LEN_MAX + 1] = ""; + char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX]; char pathType; + // start colors default to black if unspecified + char start_color_0[7] = "000000"; + char start_color_1[7] = "000000"; + char start_color_2[7] = "000000"; + char start_color_3[7] = "000000"; int nextReadPos; @@ -971,6 +1122,18 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { } else { animation.progressEnabled = false; } + } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s %d %d", + dynamicColoringPartNameBuffer, + start_color_0, start_color_1, start_color_2, start_color_3, + &colorTransitionStart, &colorTransitionEnd)) { + animation.dynamicColoringEnabled = true; + parseColor(start_color_0, animation.startColors[0]); + parseColor(start_color_1, animation.startColors[1]); + parseColor(start_color_2, animation.startColors[2]); + parseColor(start_color_3, animation.startColors[3]); + animation.colorTransitionStart = colorTransitionStart; + animation.colorTransitionEnd = colorTransitionEnd; + dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer); } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n", &pathType, &count, &pause, path, &nextReadPos) >= 4) { if (pathType == 'f') { @@ -983,6 +1146,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { // "clockPos1=%s, clockPos2=%s", // pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2); Animation::Part part; + if (path == dynamicColoringPartName) { + // Part is specified to use dynamic coloring. + part.useDynamicColoring = true; + part.postDynamicColoring = false; + postDynamicColoring = true; + } else { + // Part does not use dynamic coloring. + part.useDynamicColoring = false; + part.postDynamicColoring = postDynamicColoring; + } part.playUntilComplete = pathType == 'c'; part.framesToFadeCount = framesToFadeCount; part.count = count; @@ -1166,19 +1339,16 @@ bool BootAnimation::movie() { // Blend required to draw time on top of animation frames. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); - glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_TEXTURE_2D); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - + glBindTexture(GL_TEXTURE_2D, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); bool clockFontInitialized = false; if (mClockEnabled) { clockFontInitialized = @@ -1193,6 +1363,10 @@ bool BootAnimation::movie() { mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL); } + if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) { + initDynamicColors(); + } + playAnimation(*mAnimation); if (mTimeCheckThread != nullptr) { @@ -1218,6 +1392,55 @@ bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part, (lastDisplayedProgress == 0 || lastDisplayedProgress == 100); } +// Linear mapping from range to range +float mapLinear(float x, float a1, float a2, float b1, float b2) { + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); +} + +void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) { + // 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); + // Update quad vertex positions. + quadPositions[0] = x0; + quadPositions[1] = y0; + quadPositions[2] = x1; + quadPositions[3] = y0; + quadPositions[4] = x1; + quadPositions[5] = y1; + quadPositions[6] = x1; + quadPositions[7] = y1; + quadPositions[8] = x0; + quadPositions[9] = y1; + quadPositions[10] = x0; + quadPositions[11] = y0; + glDrawArrays(GL_TRIANGLES, 0, + sizeof(quadPositions) / sizeof(quadPositions[0]) / 2); +} + +void BootAnimation::initDynamicColors() { + for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { + parseColorDecimalString( + android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""), + mAnimation->endColors[i], mAnimation->startColors[i]); + } + glUseProgram(mImageShader); + SLOGI("[BootAnimation] Dynamically coloring boot animation."); + for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { + float *startColor = mAnimation->startColors[i]; + float *endColor = mAnimation->endColors[i]; + glUniform4f(glGetUniformLocation(mImageShader, + (U_START_COLOR_PREFIX + std::to_string(i)).c_str()), + startColor[0], startColor[1], startColor[2], 1 /* alpha */); + glUniform4f(glGetUniformLocation(mImageShader, + (U_END_COLOR_PREFIX + std::to_string(i)).c_str()), + endColor[0], endColor[1], endColor[2], 1 /* alpha */); + } + mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS); +} + bool BootAnimation::playAnimation(const Animation& animation) { const size_t pcount = animation.parts.size(); nsecs_t frameDuration = s2ns(1) / animation.fps; @@ -1230,7 +1453,6 @@ bool BootAnimation::playAnimation(const Animation& animation) { for (size_t i=0 ; i 0) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { - if (part.count != 1) { - glGenTextures(1, &frame.tid); - glBindTexture(GL_TEXTURE_2D, frame.tid); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } + glGenTextures(1, &frame.tid); + glBindTexture(GL_TEXTURE_2D, frame.tid); int w, h; - initTexture(frame.map, &w, &h); + // Set decoding option to alpha unpremultiplied so that the R, G, B channels + // of transparent pixels are preserved. + initTexture(frame.map, &w, &h, false /* don't premultiply alpha */); } const int xc = animationX + frame.trimX; const int yc = animationY + frame.trimY; - Region clearReg(Rect(mWidth, mHeight)); - clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight)); - if (!clearReg.isEmpty()) { - Region::const_iterator head(clearReg.begin()); - Region::const_iterator tail(clearReg.end()); - glEnable(GL_SCISSOR_TEST); - while (head != tail) { - const Rect& r2(*head++); - glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height()); - glClear(GL_COLOR_BUFFER_BIT); - } - glDisable(GL_SCISSOR_TEST); - } + 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 + frame.trimHeight); - glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight); + float fade = 0; // if the part hasn't been stopped yet then continue fading if necessary if (exitPending() && part.hasFadingPhase()) { - fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part, - ++fadedFramesCount); + fade = static_cast(++fadedFramesCount) / part.framesToFadeCount; if (fadedFramesCount >= part.framesToFadeCount) { 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, frame.trimWidth, frame.trimHeight); + glDisable(GL_BLEND); if (mClockEnabled && mTimeIsAccurate && validClock(part)) { drawClock(animation.clockFont, part.clockPosX, part.clockPosY); diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index f8a31c6d8790..7a597da533ee 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -31,7 +31,7 @@ #include #include -#include +#include namespace android { @@ -53,7 +53,7 @@ public: }; struct Font { - FileMap* map; + FileMap* map = nullptr; Texture texture; int char_width; int char_height; @@ -62,7 +62,7 @@ public: struct Animation { struct Frame { String8 name; - FileMap* map; + FileMap* map = nullptr; int trimX; int trimY; int trimWidth; @@ -90,6 +90,10 @@ public: uint8_t* audioData; int audioLength; Animation* animation; + // Controls if dynamic coloring is enabled for this part. + bool useDynamicColoring = false; + // Defines if this part is played after the dynamic coloring part. + bool postDynamicColoring = false; bool hasFadingPhase() const { return !playUntilComplete && framesToFadeCount > 0; @@ -105,6 +109,12 @@ public: ZipFileRO* zip; Font clockFont; Font progressFont; + // Controls if dynamic coloring is enabled for the whole animation. + bool dynamicColoringEnabled = false; + int colorTransitionStart = 0; // Start frame of dynamic color transition. + int colorTransitionEnd = 0; // End frame of dynamic color transition. + float startColors[4][3]; // Start colors of dynamic color transition. + float endColors[4][3]; // End colors of dynamic color transition. }; // All callbacks will be called from this class's internal thread. @@ -163,9 +173,12 @@ private: int displayEventCallback(int fd, int events, void* data); void processDisplayEvents(); - status_t initTexture(Texture* texture, AssetManager& asset, const char* name); - status_t initTexture(FileMap* map, int* width, int* height); + status_t initTexture(Texture* texture, AssetManager& asset, const char* name, + bool premultiplyAlpha = true); + status_t initTexture(FileMap* map, int* width, int* height, + bool premultiplyAlpha = true); status_t initFont(Font* font, const char* fallback); + void initShaders(); bool android(); bool movie(); void drawText(const char* str, const Font& font, bool bold, int* x, int* y); @@ -173,6 +186,7 @@ private: void drawProgress(int percent, const Font& font, const int xPos, const int yPos); 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); bool validClock(const Animation::Part& part); Animation* loadAnimation(const String8&); bool playAnimation(const Animation&); @@ -192,6 +206,7 @@ private: void checkExit(); void handleViewport(nsecs_t timestep); + void initDynamicColors(); sp mSession; AssetManager mAssets; @@ -218,6 +233,13 @@ private: sp mTimeCheckThread = nullptr; sp mCallbacks; Animation* mAnimation = nullptr; + GLuint mImageShader; + GLuint mTextShader; + GLuint mImageFadeLocation; + GLuint mImageTextureLocation; + GLuint mTextCropAreaLocation; + GLuint mTextTextureLocation; + GLuint mImageColorProgressLocation; }; // --------------------------------------------------------------------------- diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS index 062ffd41348a..def9f401e51f 100644 --- a/cmds/idmap2/OWNERS +++ b/cmds/idmap2/OWNERS @@ -1,4 +1,3 @@ set noparent -toddke@google.com patb@google.com zyy@google.com diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4376d225e676..f53c5b6c9748 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -771,6 +771,11 @@ public class ActivityManager { return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND; } + /** @hide Should this process state be considered in the cache? */ + public static final boolean isProcStateCached(int procState) { + return procState >= PROCESS_STATE_CACHED_ACTIVITY; + } + /** @hide Is this a foreground service type? */ public static boolean isForegroundService(int procState) { return procState == PROCESS_STATE_FOREGROUND_SERVICE; diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 0d68df48c316..4e8480c4e113 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -156,6 +156,7 @@ public abstract class ActivityManagerInternal { /** * Update information about which app IDs are on the temp allowlist. * @param appids the updated list of appIds in temp allowlist. + * If null, it is to update only changingUid. * @param changingUid uid to add or remove to temp allowlist. * @param adding true to add to temp allowlist, false to remove from temp allowlist. * @param durationMs when adding is true, the duration to be in temp allowlist. @@ -165,7 +166,7 @@ public abstract class ActivityManagerInternal { * @param callingUid the callingUid that setup this temp allowlist, only valid when param adding * is true. */ - public abstract void updateDeviceIdleTempAllowlist(int[] appids, int changingUid, + public abstract void updateDeviceIdleTempAllowlist(@Nullable int[] appids, int changingUid, boolean adding, long durationMs, @TempAllowListType int type, @ReasonCode int reasonCode, @Nullable String reason, int callingUid); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index bfff27a82f5b..3b0a5f3e9bdd 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4906,7 +4906,8 @@ public final class ActivityThread extends ClientTransactionHandler Slog.w(TAG, "Activity top position already set to onTop=" + onTop); return; } - throw new IllegalStateException("Activity top position already set to onTop=" + onTop); + // TODO(b/197484331): Remove this short-term workaround while fixing the binder failure. + Slog.e(TAG, "Activity top position already set to onTop=" + onTop); } r.isTopResumedActivity = onTop; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index c36b585d3183..9272e45c3278 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2735,10 +2735,13 @@ class ContextImpl extends Context { // need to override their display in ResourcesManager. baseContext.mForceDisplayOverrideInResources = false; baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT; - baseContext.mDisplay = display; final Resources windowContextResources = createWindowContextResources(baseContext); baseContext.setResources(windowContextResources); + // Associate the display with window context resources so that configuration update from + // the server side will also apply to the display's metrics. + baseContext.mDisplay = ResourcesManager.getInstance() + .getAdjustedDisplay(display.getDisplayId(), windowContextResources); return baseContext; } diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java index 5964f71d28db..babeb08caff7 100644 --- a/core/java/android/app/GameManager.java +++ b/core/java/android/app/GameManager.java @@ -135,6 +135,7 @@ public final class GameManager { throw e.rethrowFromSystemServer(); } } + /** * Returns a list of supported game modes for a given package. *

@@ -151,4 +152,20 @@ public final class GameManager { } } + /** + * Returns if ANGLE is enabled for a given package. + *

+ * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}. + * + * @hide + */ + @UserHandleAware + @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) + public @GameMode boolean isAngleEnabled(@NonNull String packageName) { + try { + return mService.getAngleEnabled(packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl index 4bf8a3f77bca..189f0a2fca23 100644 --- a/core/java/android/app/IGameManagerService.aidl +++ b/core/java/android/app/IGameManagerService.aidl @@ -23,4 +23,5 @@ interface IGameManagerService { int getGameMode(String packageName, int userId); void setGameMode(String packageName, int gameMode, int userId); int[] getAvailableGameModes(String packageName); + boolean getAngleEnabled(String packageName, int userId); } \ No newline at end of file diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 4b054f49d910..61b1abe25ca2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1884,6 +1884,14 @@ public class Notification implements Parcelable * clicks. To launch an activity in those cases, provide a {@link PendingIntent} for the * activity itself. * + *

How an Action is displayed, including whether the {@code icon}, {@code text}, or + * both are displayed or required, depends on where and how the action is used, and the + * {@link Style} applied to the Notification. + * + *

When the {@code title} is a {@link android.text.Spanned}, any colors set by a + * {@link ForegroundColorSpan} or {@link TextAppearanceSpan} may be removed or displayed + * with an altered in luminance to ensure proper contrast within the Notification. + * * @param icon icon to show for this action * @param title the title of the action * @param intent the {@link PendingIntent} to fire when users trigger this action @@ -5387,8 +5395,8 @@ public class Notification implements Parcelable contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor); // Use different highlighted colors for conversations' unread count if (p.mHighlightExpander) { - pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor); - textColor = Colors.flattenAlpha(bgColor, pillColor); + pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor); + textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor); } contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor); contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor); @@ -6121,21 +6129,22 @@ public class Notification implements Parcelable if (emphasizedMode) { // change the background bgColor CharSequence title = action.title; - ColorStateList[] outResultColor = new ColorStateList[1]; int buttonFillColor = getColors(p).getSecondaryAccentColor(); if (isLegacy()) { title = ContrastColorUtil.clearColorSpans(title); } else { - int notifBackgroundColor = getColors(p).getBackgroundColor(); - title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor); + // Check for a full-length span color to use as the button fill color. + Integer fullLengthColor = getFullLengthSpanColor(title); + if (fullLengthColor != null) { + // Ensure the custom button fill has 1.3:1 contrast w/ notification bg. + int notifBackgroundColor = getColors(p).getBackgroundColor(); + buttonFillColor = ensureButtonFillContrast( + fullLengthColor, notifBackgroundColor); + } + // Remove full-length color spans and ensure text contrast with the button fill. + title = ensureColorSpanContrast(title, buttonFillColor); } button.setTextViewText(R.id.action0, processTextSpans(title)); - boolean hasColorOverride = outResultColor[0] != null; - if (hasColorOverride) { - // There's a span spanning the full text, let's take it and use it as the - // background color - buttonFillColor = outResultColor[0].getDefaultColor(); - } final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext, buttonFillColor, mInNightMode); button.setTextColor(R.id.action0, textColor); @@ -6168,17 +6177,58 @@ public class Notification implements Parcelable } /** - * Ensures contrast on color spans against a background color. also returns the color of the - * text if a span was found that spans over the whole text. + * Extract the color from a full-length span from the text. + * + * @param charSequence the charSequence containing spans + * @return the raw color of the text's last full-length span containing a color, or null if + * no full-length span sets the text color. + * @hide + */ + @VisibleForTesting + @Nullable + public static Integer getFullLengthSpanColor(CharSequence charSequence) { + // NOTE: this method preserves the functionality that for a CharSequence with multiple + // full-length spans, the color of the last one is used. + Integer result = null; + if (charSequence instanceof Spanned) { + Spanned ss = (Spanned) charSequence; + Object[] spans = ss.getSpans(0, ss.length(), Object.class); + // First read through all full-length spans to get the button fill color, which will + // be used as the background color for ensuring contrast of non-full-length spans. + for (Object span : spans) { + int spanStart = ss.getSpanStart(span); + int spanEnd = ss.getSpanEnd(span); + boolean fullLength = (spanEnd - spanStart) == charSequence.length(); + if (!fullLength) { + continue; + } + if (span instanceof TextAppearanceSpan) { + TextAppearanceSpan originalSpan = (TextAppearanceSpan) span; + ColorStateList textColor = originalSpan.getTextColor(); + if (textColor != null) { + result = textColor.getDefaultColor(); + } + } else if (span instanceof ForegroundColorSpan) { + ForegroundColorSpan originalSpan = (ForegroundColorSpan) span; + result = originalSpan.getForegroundColor(); + } + } + } + return result; + } + + /** + * Ensures contrast on color spans against a background color. + * Note that any full-length color spans will be removed instead of being contrasted. * * @param charSequence the charSequence on which the spans are * @param background the background color to ensure the contrast against - * @param outResultColor an array in which a color will be returned as the first element if - * there exists a full length color span. * @return the contrasted charSequence + * @hide */ - private static CharSequence ensureColorSpanContrast(CharSequence charSequence, - int background, ColorStateList[] outResultColor) { + @VisibleForTesting + public static CharSequence ensureColorSpanContrast(CharSequence charSequence, + int background) { if (charSequence instanceof Spanned) { Spanned ss = (Spanned) charSequence; Object[] spans = ss.getSpans(0, ss.length(), Object.class); @@ -6195,19 +6245,19 @@ public class Notification implements Parcelable TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; ColorStateList textColor = originalSpan.getTextColor(); if (textColor != null) { - int[] colors = textColor.getColors(); - int[] newColors = new int[colors.length]; - for (int i = 0; i < newColors.length; i++) { - boolean isBgDark = isColorDark(background); - newColors[i] = ContrastColorUtil.ensureLargeTextContrast( - colors[i], background, isBgDark); - } - textColor = new ColorStateList(textColor.getStates().clone(), - newColors); if (fullLength) { - outResultColor[0] = textColor; // Let's drop the color from the span textColor = null; + } else { + int[] colors = textColor.getColors(); + int[] newColors = new int[colors.length]; + for (int i = 0; i < newColors.length; i++) { + boolean isBgDark = isColorDark(background); + newColors[i] = ContrastColorUtil.ensureLargeTextContrast( + colors[i], background, isBgDark); + } + textColor = new ColorStateList(textColor.getStates().clone(), + newColors); } resultSpan = new TextAppearanceSpan( originalSpan.getFamily(), @@ -6217,15 +6267,14 @@ public class Notification implements Parcelable originalSpan.getLinkTextColor()); } } else if (resultSpan instanceof ForegroundColorSpan) { - ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan; - int foregroundColor = originalSpan.getForegroundColor(); - boolean isBgDark = isColorDark(background); - foregroundColor = ContrastColorUtil.ensureLargeTextContrast( - foregroundColor, background, isBgDark); if (fullLength) { - outResultColor[0] = ColorStateList.valueOf(foregroundColor); resultSpan = null; } else { + ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan; + int foregroundColor = originalSpan.getForegroundColor(); + boolean isBgDark = isColorDark(background); + foregroundColor = ContrastColorUtil.ensureLargeTextContrast( + foregroundColor, background, isBgDark); resultSpan = new ForegroundColorSpan(foregroundColor); } } else { @@ -6247,12 +6296,28 @@ public class Notification implements Parcelable * * @param color the color to check * @return true if the color has higher contrast with white than black + * @hide */ - private static boolean isColorDark(int color) { + public static boolean isColorDark(int color) { // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint. return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474; } + /** + * Finds a button fill color with sufficient contrast over bg (1.3:1) that has the same hue + * as the original color, but is lightened or darkened depending on whether the background + * is dark or light. + * + * @hide + */ + @VisibleForTesting + public static int ensureButtonFillContrast(int color, int bg) { + return isColorDark(bg) + ? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, 1.3) + : ContrastColorUtil.findContrastColor(color, bg, true, 1.3); + } + + /** * @return Whether we are currently building a notification from a legacy (an app that * doesn't create material notifications by itself) app. @@ -6441,25 +6506,34 @@ public class Notification implements Parcelable if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N && !styleDisplaysCustomViewInline()) { - if (mN.contentView == null) { - mN.contentView = createContentView(); + RemoteViews newContentView = mN.contentView; + RemoteViews newBigContentView = mN.bigContentView; + RemoteViews newHeadsUpContentView = mN.headsUpContentView; + if (newContentView == null) { + newContentView = createContentView(); mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, - mN.contentView.getSequenceNumber()); + newContentView.getSequenceNumber()); } - if (mN.bigContentView == null) { - mN.bigContentView = createBigContentView(); - if (mN.bigContentView != null) { + if (newBigContentView == null) { + newBigContentView = createBigContentView(); + if (newBigContentView != null) { mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, - mN.bigContentView.getSequenceNumber()); + newBigContentView.getSequenceNumber()); } } - if (mN.headsUpContentView == null) { - mN.headsUpContentView = createHeadsUpContentView(); - if (mN.headsUpContentView != null) { + if (newHeadsUpContentView == null) { + newHeadsUpContentView = createHeadsUpContentView(); + if (newHeadsUpContentView != null) { mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, - mN.headsUpContentView.getSequenceNumber()); + newHeadsUpContentView.getSequenceNumber()); } } + // Don't set any of the content views until after they have all been generated, + // to avoid the generated .contentView triggering the logic which skips generating + // the .bigContentView. + mN.contentView = newContentView; + mN.bigContentView = newBigContentView; + mN.headsUpContentView = newHeadsUpContentView; } if ((mN.defaults & DEFAULT_LIGHTS) != 0) { @@ -12305,6 +12379,8 @@ public class Notification implements Parcelable private int mSecondaryTextColor = COLOR_INVALID; private int mPrimaryAccentColor = COLOR_INVALID; private int mSecondaryAccentColor = COLOR_INVALID; + private int mTertiaryAccentColor = COLOR_INVALID; + private int mOnAccentTextColor = COLOR_INVALID; private int mErrorColor = COLOR_INVALID; private int mContrastColor = COLOR_INVALID; private int mRippleAlpha = 0x33; @@ -12362,7 +12438,7 @@ public class Notification implements Parcelable if (isColorized) { if (rawColor == COLOR_DEFAULT) { - int[] attrs = {R.attr.colorAccentTertiary}; + int[] attrs = {R.attr.colorAccentSecondary}; try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { mBackgroundColor = getColor(ta, 0, Color.WHITE); } @@ -12379,6 +12455,8 @@ public class Notification implements Parcelable mContrastColor = mPrimaryTextColor; mPrimaryAccentColor = mPrimaryTextColor; mSecondaryAccentColor = mSecondaryTextColor; + mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor); + mOnAccentTextColor = mBackgroundColor; mErrorColor = mPrimaryTextColor; mRippleAlpha = 0x33; } else { @@ -12389,6 +12467,8 @@ public class Notification implements Parcelable R.attr.textColorSecondary, R.attr.colorAccent, R.attr.colorAccentSecondary, + R.attr.colorAccentTertiary, + R.attr.textColorOnAccent, R.attr.colorError, R.attr.colorControlHighlight }; @@ -12399,8 +12479,10 @@ public class Notification implements Parcelable mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID); mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID); mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID); - mErrorColor = getColor(ta, 6, COLOR_INVALID); - mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff)); + mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID); + mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID); + mErrorColor = getColor(ta, 8, COLOR_INVALID); + mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff)); } mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor, mBackgroundColor, nightMode); @@ -12420,6 +12502,14 @@ public class Notification implements Parcelable if (mSecondaryAccentColor == COLOR_INVALID) { mSecondaryAccentColor = mContrastColor; } + if (mTertiaryAccentColor == COLOR_INVALID) { + mTertiaryAccentColor = mContrastColor; + } + if (mOnAccentTextColor == COLOR_INVALID) { + mOnAccentTextColor = ColorUtils.setAlphaComponent( + ContrastColorUtil.resolvePrimaryColor( + ctx, mTertiaryAccentColor, nightMode), 0xFF); + } if (mErrorColor == COLOR_INVALID) { mErrorColor = mPrimaryTextColor; } @@ -12485,6 +12575,16 @@ public class Notification implements Parcelable return mSecondaryAccentColor; } + /** @return the theme's tertiary accent color for colored UI elements. */ + public @ColorInt int getTertiaryAccentColor() { + return mTertiaryAccentColor; + } + + /** @return the theme's text color to be used on the tertiary accent color. */ + public @ColorInt int getOnAccentTextColor() { + return mOnAccentTextColor; + } + /** * @return the contrast-adjusted version of the color provided by the app, or the * primary text color when colorized. diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 1837fb860b73..6553b61ebbc2 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -260,8 +260,6 @@ public final class NotificationChannel implements Parcelable { private boolean mDemoted = false; private boolean mImportantConvo = false; private long mDeletedTime = DEFAULT_DELETION_TIME_MS; - // If the sound for this channel is missing, e.g. after restore. - private boolean mIsSoundMissing; /** * Creates a notification channel. @@ -716,13 +714,6 @@ public final class NotificationChannel implements Parcelable { return mSound; } - /** - * @hide - */ - public boolean isSoundMissing() { - return mIsSoundMissing; - } - /** * Returns the audio attributes for sound played by notifications posted to this channel. */ @@ -1007,9 +998,8 @@ public final class NotificationChannel implements Parcelable { // according to the docs because canonicalize method has to handle canonical uris as well. Uri canonicalizedUri = contentResolver.canonicalize(uri); if (canonicalizedUri == null) { - // We got a null because the uri in the backup does not exist here. - mIsSoundMissing = true; - return null; + // We got a null because the uri in the backup does not exist here, so we return default + return Settings.System.DEFAULT_NOTIFICATION_URI; } return contentResolver.uncanonicalize(canonicalizedUri); } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 8d332ab1d58b..6cfa39cd2337 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -559,6 +559,53 @@ public class WallpaperManager { return null; } + public Rect peekWallpaperDimensions(Context context, boolean returnDefault, int userId) { + if (mService != null) { + try { + if (!mService.isWallpaperSupported(context.getOpPackageName())) { + return new Rect(); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + Rect dimensions = null; + synchronized (this) { + try { + Bundle params = new Bundle(); + // Let's peek user wallpaper first. + ParcelFileDescriptor pfd = mService.getWallpaperWithFeature( + context.getOpPackageName(), context.getAttributionTag(), this, + FLAG_SYSTEM, params, userId); + if (pfd != null) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, options); + dimensions = new Rect(0, 0, options.outWidth, options.outHeight); + } + } catch (RemoteException ex) { + Log.w(TAG, "peek wallpaper dimensions failed", ex); + } + } + // If user wallpaper is unavailable, may be the default one instead. + if ((dimensions == null || dimensions.width() == 0 || dimensions.height() == 0) + && returnDefault) { + InputStream is = openDefaultWallpaper(context, FLAG_SYSTEM); + if (is != null) { + try { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(is, null, options); + dimensions = new Rect(0, 0, options.outWidth, options.outHeight); + } finally { + IoUtils.closeQuietly(is); + } + } + } + return dimensions; + } + void forgetLoadedWallpaper() { synchronized (this) { mCachedWallpaper = null; @@ -1038,6 +1085,17 @@ public class WallpaperManager { return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy); } + /** + * Peek the dimensions of system wallpaper of the user without decoding it. + * + * @return the dimensions of system wallpaper + * @hide + */ + public Rect peekBitmapDimensions() { + return sGlobals.peekWallpaperDimensions( + mContext, true /* returnDefault */, mContext.getUserId()); + } + /** * Get an open, readable file descriptor to the given wallpaper image file. * The caller is responsible for closing the file descriptor when done ingesting the file. diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 0e04ad3768c7..0fe80c45ad2a 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9733,6 +9733,27 @@ public class DevicePolicyManager { return null; } + /** + * @param userId The user for whom to retrieve information. + * @param restriction The restriction enforced by admin. It could be any user restriction or + * policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and + * {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}. + * @return Details of admin and user which enforced the restriction for the userId. If + * restriction is null, profile owner for the user or device owner info is returned. + * @hide + */ + public @Nullable Bundle getEnforcingAdminAndUserDetails(int userId, + @Nullable String restriction) { + if (mService != null) { + try { + return mService.getEnforcingAdminAndUserDetails(userId, restriction); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + /** * Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and * actual package file remain. This function can be called by a device owner, profile owner, or diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index fdc4a165ffa3..d287437b143b 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -251,6 +251,7 @@ interface IDevicePolicyManager { boolean isNotificationListenerServicePermitted(in String packageName, int userId); Intent createAdminSupportIntent(in String restriction); + Bundle getEnforcingAdminAndUserDetails(int userId,String restriction); boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent); boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent); diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index dae565e12fd7..67f631f98f0b 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -280,6 +280,32 @@ public class BackupManager { } } + /** + * Convenience method for callers who need to indicate that some other package or + * some other user needs a backup pass. This can be useful in the case of groups of + * packages that share a uid and/or have user-specific data. + *

+ * This method requires that the application hold the "android.permission.BACKUP" + * permission if the package named in the package argument does not run under the + * same uid as the caller. This method also requires that the application hold the + * "android.permission.INTERACT_ACROSS_USERS_FULL" if the user argument is not the + * same as the user the caller is running under. + * @param userId The user to back up + * @param packageName The package name identifying the application to back up. + * + * @hide + */ + public static void dataChangedForUser(int userId, String packageName) { + checkServiceBinder(); + if (sService != null) { + try { + sService.dataChangedForUser(userId, packageName); + } catch (RemoteException e) { + Log.e(TAG, "dataChanged(userId,pkg) couldn't connect"); + } + } + } + /** * @deprecated Applications shouldn't request a restore operation using this method. In Android * P and later, this method is a no-op. diff --git a/core/java/android/app/search/Query.java b/core/java/android/app/search/Query.java index c64e10723ca6..f073b4e50555 100644 --- a/core/java/android/app/search/Query.java +++ b/core/java/android/app/search/Query.java @@ -70,7 +70,7 @@ public final class Query implements Parcelable { @NonNull Bundle extras) { mInput = input; mTimestampMillis = timestampMillis; - mExtras = extras == null ? extras : new Bundle(); + mExtras = extras != null ? extras : new Bundle(); } /** diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 063ba1174cdc..2e94dd1a47c4 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -143,7 +143,7 @@ public class AppWidgetProviderInfo implements Parcelable { public ComponentName provider; /** - * The default height of the widget when added to a host, in dp. The widget will get + * The default height of the widget when added to a host, in px. The widget will get * at least this width, and will often be given more, depending on the host. * *

This field corresponds to the android:minWidth attribute in @@ -152,7 +152,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minWidth; /** - * The default height of the widget when added to a host, in dp. The widget will get + * The default height of the widget when added to a host, in px. The widget will get * at least this height, and will often be given more, depending on the host. * *

This field corresponds to the android:minHeight attribute in @@ -161,7 +161,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minHeight; /** - * Minimum width (in dp) which the widget can be resized to. This field has no effect if it + * Minimum width (in px) which the widget can be resized to. This field has no effect if it * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}). * *

This field corresponds to the android:minResizeWidth attribute in @@ -170,7 +170,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minResizeWidth; /** - * Minimum height (in dp) which the widget can be resized to. This field has no effect if it + * Minimum height (in px) which the widget can be resized to. This field has no effect if it * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}). * *

This field corresponds to the android:minResizeHeight attribute in @@ -179,7 +179,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minResizeHeight; /** - * Maximum width (in dp) which the widget can be resized to. This field has no effect if it is + * Maximum width (in px) which the widget can be resized to. This field has no effect if it is * smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}). * *

This field corresponds to the android:maxResizeWidth attribute in the @@ -189,7 +189,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int maxResizeWidth; /** - * Maximum height (in dp) which the widget can be resized to. This field has no effect if it is + * Maximum height (in px) which the widget can be resized to. This field has no effect if it is * smaller than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}). * *

This field corresponds to the android:maxResizeHeight attribute in the diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 6885c10b4889..ca5b63fdeec9 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3286,7 +3286,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O} * or higher are not allowed to start background services from the background. * See - * + * * Background Execution Limits * for more details. * @@ -3295,7 +3295,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * or higher are not allowed to start foreground services from the background. * See - * + * * Behavior changes: Apps targeting Android 12 * * for more details. @@ -3349,7 +3349,7 @@ public abstract class Context { * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * or higher are not allowed to start foreground services from the background. * See - * + * * Behavior changes: Apps targeting Android 12 * * for more details. @@ -6026,6 +6026,10 @@ public abstract class Context { * more general access to the URI's content provider then this check will * always fail. * + * Note: On SDK Version {@link android.os.Build.VERSION_CODES#S}, + * calling this method from a secondary-user's context will incorrectly return + * {@link PackageManager#PERMISSION_DENIED} for all {code uris}. + * * @param uris The list of URIs that is being checked. * @param pid The process ID being checked against. Must be > 0. * @param uid The user ID being checked against. A uid of 0 is the root diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e781c2fce2b2..1552dbd00c92 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2742,6 +2742,22 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED"; + /** + * Broadcast Action: One of the suspend conditions have been modified for the packages. + *

Includes the following extras: + *

    + *
  • {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been modified + *
  • {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been modified + *
+ * + *

This is a protected intent that can only be sent + * by the system. It is only sent to registered receivers. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PACKAGES_SUSPENSION_CHANGED = + "android.intent.action.PACKAGES_SUSPENSION_CHANGED"; /** * Broadcast Action: Distracting packages have been changed. diff --git a/core/java/android/content/integrity/OWNERS b/core/java/android/content/integrity/OWNERS index 20c758aedd67..a1fe59c862d2 100644 --- a/core/java/android/content/integrity/OWNERS +++ b/core/java/android/content/integrity/OWNERS @@ -1,5 +1,3 @@ # Bug component: 722021 -toddke@android.com -toddke@google.com patb@google.com diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS index 3669817e9844..9c473360a46a 100644 --- a/core/java/android/content/om/OWNERS +++ b/core/java/android/content/om/OWNERS @@ -1,6 +1,4 @@ # Bug component: 568631 -toddke@android.com -toddke@google.com patb@google.com zyy@google.com diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS index 4e674f6ec9a8..128bfb99ccd4 100644 --- a/core/java/android/content/pm/OWNERS +++ b/core/java/android/content/pm/OWNERS @@ -1,11 +1,9 @@ # Bug component: 36137 -toddke@android.com -toddke@google.com patb@google.com per-file PackageParser.java = set noparent -per-file PackageParser.java = chiuwinson@google.com,patb@google.com,toddke@google.com +per-file PackageParser.java = chiuwinson@google.com,patb@google.com per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS diff --git a/core/java/android/content/pm/dex/OWNERS b/core/java/android/content/pm/dex/OWNERS index 267e5d58f9a6..b590f659a5d4 100644 --- a/core/java/android/content/pm/dex/OWNERS +++ b/core/java/android/content/pm/dex/OWNERS @@ -1,7 +1,5 @@ # Bug component: 86431 -toddke@android.com -toddke@google.com patb@google.com calin@google.com ngeoffray@google.com diff --git a/core/java/android/content/pm/parsing/OWNERS b/core/java/android/content/pm/parsing/OWNERS index 8049d5cb7fa2..445a8330037b 100644 --- a/core/java/android/content/pm/parsing/OWNERS +++ b/core/java/android/content/pm/parsing/OWNERS @@ -2,4 +2,3 @@ chiuwinson@google.com patb@google.com -toddke@google.com diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS index cf7e6890876a..f9c51dd2ae58 100644 --- a/core/java/android/content/pm/permission/OWNERS +++ b/core/java/android/content/pm/permission/OWNERS @@ -2,7 +2,5 @@ include platform/frameworks/base:/core/java/android/permission/OWNERS -toddke@android.com -toddke@google.com patb@google.com diff --git a/core/java/android/content/pm/split/OWNERS b/core/java/android/content/pm/split/OWNERS index 3d126d297e60..b8fa1a93ed78 100644 --- a/core/java/android/content/pm/split/OWNERS +++ b/core/java/android/content/pm/split/OWNERS @@ -1,5 +1,3 @@ # Bug component: 36137 -toddke@android.com -toddke@google.com patb@google.com diff --git a/core/java/android/content/pm/verify/domain/OWNERS b/core/java/android/content/pm/verify/domain/OWNERS index c669112e0512..445a8330037b 100644 --- a/core/java/android/content/pm/verify/domain/OWNERS +++ b/core/java/android/content/pm/verify/domain/OWNERS @@ -2,4 +2,3 @@ chiuwinson@google.com patb@google.com -toddke@google.com \ No newline at end of file diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS index d12d920b2a54..7460a14182e5 100644 --- a/core/java/android/content/res/OWNERS +++ b/core/java/android/content/res/OWNERS @@ -1,6 +1,4 @@ # Bug component: 568761 -toddke@android.com -toddke@google.com patb@google.com zyy@google.com diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS index 2b4e4a106cec..75b42d4b64e1 100644 --- a/core/java/android/hardware/OWNERS +++ b/core/java/android/hardware/OWNERS @@ -1,5 +1,5 @@ # Camera -per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com +per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com # Sensor Privacy per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 3f3db29ed0fd..c8c122da4ab8 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -438,9 +438,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener { + private final long mAuthRequestId; + + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelAuthentication(); + Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } @@ -853,10 +860,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @param userId The user to authenticate * @param operationId The keystore operation associated with authentication * + * @return A requestId that can be used to cancel this operation. + * * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) - public void authenticateUserForOperation( + public long authenticateUserForOperation( @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback, @@ -871,7 +880,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } - authenticateInternal(operationId, cancel, executor, callback, userId); + + return authenticateInternal(operationId, cancel, executor, callback, userId); } /** @@ -1002,10 +1012,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId()); } - private void cancelAuthentication() { + private void cancelAuthentication(long requestId) { if (mService != null) { try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { Log.e(TAG, "Unable to cancel authentication", e); } @@ -1024,7 +1034,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan authenticateInternal(operationId, cancel, executor, callback, userId); } - private void authenticateInternal( + private long authenticateInternal( long operationId, @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @@ -1040,9 +1050,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan try { if (cancel.isCanceled()) { Log.w(TAG, "Authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener()); + return -1; } mExecutor = executor; @@ -1065,14 +1073,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan promptInfo = mPromptInfo; } - mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, - mContext.getOpPackageName(), promptInfo); - + final long authId = mService.authenticate(mToken, operationId, userId, + mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo); + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + return authId; } catch (RemoteException e) { Log.e(TAG, "Remote exception while authenticating", e); mExecutor.execute(() -> callback.onAuthenticationError( BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, mContext.getString(R.string.biometric_error_hw_unavailable))); + return -1; } } diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl index 4c2a9ae10cbd..91f794c161bf 100644 --- a/core/java/android/hardware/biometrics/IAuthService.aidl +++ b/core/java/android/hardware/biometrics/IAuthService.aidl @@ -41,13 +41,14 @@ interface IAuthService { // Retrieve the package where BIometricOrompt's UI is implemented String getUiPackage(); - // Requests authentication. The service choose the appropriate biometric to use, and show - // the corresponding BiometricDialog. - void authenticate(IBinder token, long sessionId, int userId, + // Requests authentication. The service chooses the appropriate biometric to use, and shows + // the corresponding BiometricDialog. A requestId is returned that can be used to cancel + // this operation. + long authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics. // Checks if biometrics can be used. diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index 876513f266e8..addd622eef35 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -48,13 +48,13 @@ interface IBiometricAuthenticator { // startPreparedClient(). void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication); + long requestId, int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int cookie); - // Cancels authentication. - void cancelAuthenticationFromService(IBinder token, String opPackageName); + // Cancels authentication for the given requestId. + void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId); // Determine if HAL is loaded and ready boolean isHardwareDetected(String opPackageName); diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index 64b51183a170..2c3c8c353e8c 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -36,13 +36,14 @@ interface IBiometricService { // Retrieve static sensor properties for all biometric sensors List getSensorProperties(String opPackageName); - // Requests authentication. The service choose the appropriate biometric to use, and show - // the corresponding BiometricDialog. - void authenticate(IBinder token, long operationId, int userId, + // Requests authentication. The service chooses the appropriate biometric to use, and shows + // the corresponding BiometricDialog. A requestId is returned that can be used to cancel + // this operation. + long authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); - // Cancel authentication for the given session. - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); // Checks if biometrics can be used. int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators); diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java index 5cfba3d945cd..395c655ddf7c 100644 --- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java @@ -263,12 +263,12 @@ public final class CameraExtensionCharacteristics { @Override public void onServiceConnected(ComponentName component, IBinder binder) { mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder); - mInitFuture.setStatus(true); try { mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported(); } catch (RemoteException e) { Log.e(TAG, "Remote IPC failed!"); } + mInitFuture.setStatus(true); } }; ctx.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java index 20ca4a338f01..032ed7e4db62 100644 --- a/core/java/android/hardware/camera2/CaptureFailure.java +++ b/core/java/android/hardware/camera2/CaptureFailure.java @@ -59,7 +59,7 @@ public class CaptureFailure { private final CaptureRequest mRequest; private final int mReason; - private final boolean mDropped; + private final boolean mWasImageCaptured; private final int mSequenceId; private final long mFrameNumber; private final String mErrorPhysicalCameraId; @@ -68,10 +68,11 @@ public class CaptureFailure { * @hide */ public CaptureFailure(CaptureRequest request, int reason, - boolean dropped, int sequenceId, long frameNumber, String errorPhysicalCameraId) { + boolean wasImageCaptured, int sequenceId, long frameNumber, + String errorPhysicalCameraId) { mRequest = request; mReason = reason; - mDropped = dropped; + mWasImageCaptured = wasImageCaptured; mSequenceId = sequenceId; mFrameNumber = frameNumber; mErrorPhysicalCameraId = errorPhysicalCameraId; @@ -141,7 +142,7 @@ public class CaptureFailure { * @return boolean True if the image was captured, false otherwise. */ public boolean wasImageCaptured() { - return !mDropped; + return mWasImageCaptured; } /** diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java index 8da6551f3d15..b8443fb6d14b 100644 --- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java @@ -873,21 +873,19 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes @Override public int submitBurst(List requests, IRequestCallback callback) { int seqId = -1; - synchronized (mInterfaceLock) { - try { - CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback); - ArrayList captureRequests = new ArrayList<>(); - for (Request request : requests) { - captureRequests.add(initializeCaptureRequest(mCameraDevice, request, - mCameraConfigMap)); - } - seqId = mCaptureSession.captureBurstRequests(captureRequests, - new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback); - } catch (CameraAccessException e) { - Log.e(TAG, "Failed to submit capture requests!"); - } catch (IllegalStateException e) { - Log.e(TAG, "Capture session closed!"); + try { + CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback); + ArrayList captureRequests = new ArrayList<>(); + for (Request request : requests) { + captureRequests.add(initializeCaptureRequest(mCameraDevice, request, + mCameraConfigMap)); } + seqId = mCaptureSession.captureBurstRequests(captureRequests, + new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback); + } catch (CameraAccessException e) { + Log.e(TAG, "Failed to submit capture requests!"); + } catch (IllegalStateException e) { + Log.e(TAG, "Capture session closed!"); } return seqId; @@ -896,18 +894,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes @Override public int setRepeating(Request request, IRequestCallback callback) { int seqId = -1; - synchronized (mInterfaceLock) { - try { - CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice, - request, mCameraConfigMap); - CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback); - seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest, - new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback); - } catch (CameraAccessException e) { - Log.e(TAG, "Failed to enable repeating request!"); - } catch (IllegalStateException e) { - Log.e(TAG, "Capture session closed!"); - } + try { + CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice, + request, mCameraConfigMap); + CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback); + seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest, + new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback); + } catch (CameraAccessException e) { + Log.e(TAG, "Failed to enable repeating request!"); + } catch (IllegalStateException e) { + Log.e(TAG, "Capture session closed!"); } return seqId; @@ -915,27 +911,23 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes @Override public void abortCaptures() { - synchronized (mInterfaceLock) { - try { - mCaptureSession.abortCaptures(); - } catch (CameraAccessException e) { - Log.e(TAG, "Failed during capture abort!"); - } catch (IllegalStateException e) { - Log.e(TAG, "Capture session closed!"); - } + try { + mCaptureSession.abortCaptures(); + } catch (CameraAccessException e) { + Log.e(TAG, "Failed during capture abort!"); + } catch (IllegalStateException e) { + Log.e(TAG, "Capture session closed!"); } } @Override public void stopRepeating() { - synchronized (mInterfaceLock) { - try { - mCaptureSession.stopRepeating(); - } catch (CameraAccessException e) { - Log.e(TAG, "Failed during repeating capture stop!"); - } catch (IllegalStateException e) { - Log.e(TAG, "Capture session closed!"); - } + try { + mCaptureSession.stopRepeating(); + } catch (CameraAccessException e) { + Log.e(TAG, "Failed during repeating capture stop!"); + } catch (IllegalStateException e) { + Log.e(TAG, "Capture session closed!"); } } } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index fc728a22ed5a..88649392c23c 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -104,6 +104,9 @@ public class CameraDeviceImpl extends CameraDevice private SparseArray mCaptureCallbackMap = new SparseArray(); + /** map request IDs which have batchedOutputs to requestCount*/ + private HashMap mBatchOutputMap = new HashMap<>(); + private int mRepeatingRequestId = REQUEST_ID_NONE; // Latest repeating request list's types private int[] mRepeatingRequestTypes; @@ -973,6 +976,7 @@ public class CameraDeviceImpl extends CameraDevice mConfiguredInput = new SimpleEntry(REQUEST_ID_NONE, null); mIdle = true; mCaptureCallbackMap = new SparseArray(); + mBatchOutputMap = new HashMap<>(); mFrameNumberTracker = new FrameNumberTracker(); mCurrentSession.closeWithoutDraining(); @@ -1179,6 +1183,41 @@ public class CameraDeviceImpl extends CameraDevice return requestTypes; } + private boolean hasBatchedOutputs(List requestList) { + boolean hasBatchedOutputs = true; + for (int i = 0; i < requestList.size(); i++) { + CaptureRequest request = requestList.get(i); + if (!request.isPartOfCRequestList()) { + hasBatchedOutputs = false; + break; + } + if (i == 0) { + Collection targets = request.getTargets(); + if (targets.size() != 2) { + hasBatchedOutputs = false; + break; + } + } + } + return hasBatchedOutputs; + } + + private void updateTracker(int requestId, long frameNumber, + int requestType, CaptureResult result, boolean isPartialResult) { + int requestCount = 1; + // If the request has batchedOutputs update each frame within the batch. + if (mBatchOutputMap.containsKey(requestId)) { + requestCount = mBatchOutputMap.get(requestId); + for (int i = 0; i < requestCount; i++) { + mFrameNumberTracker.updateTracker(frameNumber - (requestCount - 1 - i), + result, isPartialResult, requestType); + } + } else { + mFrameNumberTracker.updateTracker(frameNumber, result, + isPartialResult, requestType); + } + } + private int submitCaptureRequest(List requestList, CaptureCallback callback, Executor executor, boolean repeating) throws CameraAccessException { @@ -1224,6 +1263,14 @@ public class CameraDeviceImpl extends CameraDevice request.recoverStreamIdToSurface(); } + // If the request has batched outputs, then store the + // requestCount and requestId in the map. + boolean hasBatchedOutputs = hasBatchedOutputs(requestList); + if (hasBatchedOutputs) { + int requestCount = requestList.size(); + mBatchOutputMap.put(requestInfo.getRequestId(), requestCount); + } + if (callback != null) { mCaptureCallbackMap.put(requestInfo.getRequestId(), new CaptureCallbackHolder( @@ -1820,7 +1867,7 @@ public class CameraDeviceImpl extends CameraDevice final CaptureFailure failure = new CaptureFailure( request, reason, - /*dropped*/ mayHaveBuffers, + mayHaveBuffers, requestId, frameNumber, errorPhysicalCameraId); @@ -1839,8 +1886,18 @@ public class CameraDeviceImpl extends CameraDevice if (DEBUG) { Log.v(TAG, String.format("got error frame %d", frameNumber)); } - mFrameNumberTracker.updateTracker(frameNumber, - /*error*/true, request.getRequestType()); + + // Update FrameNumberTracker for every frame during HFR mode. + if (mBatchOutputMap.containsKey(requestId)) { + for (int i = 0; i < mBatchOutputMap.get(requestId); i++) { + mFrameNumberTracker.updateTracker(frameNumber - (subsequenceId - i), + /*error*/true, request.getRequestType()); + } + } else { + mFrameNumberTracker.updateTracker(frameNumber, + /*error*/true, request.getRequestType()); + } + checkAndFireSequenceComplete(); // Dispatch the failure callback @@ -2023,7 +2080,6 @@ public class CameraDeviceImpl extends CameraDevice public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[]) throws RemoteException { - int requestId = resultExtras.getRequestId(); long frameNumber = resultExtras.getFrameNumber(); @@ -2064,8 +2120,8 @@ public class CameraDeviceImpl extends CameraDevice + frameNumber); } - mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult, - requestType); + updateTracker(requestId, frameNumber, requestType, /*result*/null, + isPartialResult); return; } @@ -2077,8 +2133,9 @@ public class CameraDeviceImpl extends CameraDevice + frameNumber); } - mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult, - requestType); + updateTracker(requestId, frameNumber, requestType, /*result*/null, + isPartialResult); + return; } @@ -2184,9 +2241,7 @@ public class CameraDeviceImpl extends CameraDevice Binder.restoreCallingIdentity(ident); } - // Collect the partials for a total result; or mark the frame as totally completed - mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult, - requestType); + updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult); // Fire onCaptureSequenceCompleted if (!isPartialResult) { diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java index 3b1cb94a6619..425f22c31306 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java @@ -58,7 +58,7 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { private static final class JpegParameters { public HashSet mTimeStamps = new HashSet<>(); - public int mRotation = JPEG_DEFAULT_ROTATION; // CCW multiple of 90 degrees + public int mRotation = JPEG_DEFAULT_ROTATION; // CW multiple of 90 degrees public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100] } @@ -100,7 +100,8 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { Integer orientation = captureBundles.get(0).captureResult.get( CaptureResult.JPEG_ORIENTATION); if (orientation != null) { - ret.mRotation = orientation / 90; + // The jpeg encoder expects CCW rotation, convert from CW + ret.mRotation = (360 - (orientation % 360)) / 90; } else { Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION); } diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java index c5d37c2d0b90..0dc8f92967fb 100644 --- a/core/java/android/hardware/display/BrightnessInfo.java +++ b/core/java/android/hardware/display/BrightnessInfo.java @@ -60,12 +60,18 @@ public final class BrightnessInfo implements Parcelable { /** Brightness */ public final float brightness; + /** Brightness after {@link DisplayPowerController} adjustments */ + public final float adjustedBrightness; + /** Current minimum supported brightness. */ public final float brightnessMinimum; /** Current maximum supported brightness. */ public final float brightnessMaximum; + /** Brightness values greater than this point are only used in High Brightness Mode. */ + public final float highBrightnessTransitionPoint; + /** * Current state of high brightness mode. * Can be any of HIGH_BRIGHTNESS_MODE_* values. @@ -73,11 +79,20 @@ public final class BrightnessInfo implements Parcelable { public final int highBrightnessMode; public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum, - @HighBrightnessMode int highBrightnessMode) { + @HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint) { + this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode, + highBrightnessTransitionPoint); + } + + public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum, + float brightnessMaximum, @HighBrightnessMode int highBrightnessMode, + float highBrightnessTransitionPoint) { this.brightness = brightness; + this.adjustedBrightness = adjustedBrightness; this.brightnessMinimum = brightnessMinimum; this.brightnessMaximum = brightnessMaximum; this.highBrightnessMode = highBrightnessMode; + this.highBrightnessTransitionPoint = highBrightnessTransitionPoint; } /** @@ -103,9 +118,11 @@ public final class BrightnessInfo implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeFloat(brightness); + dest.writeFloat(adjustedBrightness); dest.writeFloat(brightnessMinimum); dest.writeFloat(brightnessMaximum); dest.writeInt(highBrightnessMode); + dest.writeFloat(highBrightnessTransitionPoint); } public static final @android.annotation.NonNull Creator CREATOR = @@ -123,9 +140,11 @@ public final class BrightnessInfo implements Parcelable { private BrightnessInfo(Parcel source) { brightness = source.readFloat(); + adjustedBrightness = source.readFloat(); brightnessMinimum = source.readFloat(); brightnessMaximum = source.readFloat(); highBrightnessMode = source.readInt(); + highBrightnessTransitionPoint = source.readFloat(); } } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index e13a7b6eac65..fc8337ac3155 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -1257,6 +1257,23 @@ public final class DisplayManager { */ String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS = "fixed_refresh_rate_high_ambient_brightness_thresholds"; + + /** + * Key for refresh rate when the device is in high brightness mode for sunlight visility. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.integer#config_defaultRefreshRateInHbmSunlight + */ + String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight"; + + /** + * Key for refresh rate when the device is in high brightness mode for HDR. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.integer#config_defaultRefreshRateInHbmHdr + */ + String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr"; + /** * Key for default peak refresh rate * diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index a9b95fce8777..6c3936569c28 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -361,6 +361,11 @@ public final class DisplayManagerGlobal { for (int i = 0; i < numListeners; i++) { mask |= mDisplayListeners.get(i).mEventsMask; } + if (mDispatchNativeCallbacks) { + mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED + | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + } return mask; } @@ -1047,12 +1052,17 @@ public final class DisplayManagerGlobal { private static native void nSignalNativeCallbacks(float refreshRate); - // Called from AChoreographer via JNI. - // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. - private void registerNativeChoreographerForRefreshRateCallbacks() { + /** + * Called from AChoreographer via JNI. + * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. + * Public for unit testing to be able to call this method. + */ + @VisibleForTesting + public void registerNativeChoreographerForRefreshRateCallbacks() { synchronized (mLock) { - registerCallbackIfNeededLocked(); mDispatchNativeCallbacks = true; + registerCallbackIfNeededLocked(); + updateCallbackIfNeededLocked(); DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); if (display != null) { // We need to tell AChoreographer instances the current refresh rate so that apps @@ -1063,11 +1073,16 @@ public final class DisplayManagerGlobal { } } - // Called from AChoreographer via JNI. - // Unregisters AChoreographer from receiving refresh rate callbacks. - private void unregisterNativeChoreographerForRefreshRateCallbacks() { + /** + * Called from AChoreographer via JNI. + * Unregisters AChoreographer from receiving refresh rate callbacks. + * Public for unit testing to be able to call this method. + */ + @VisibleForTesting + public void unregisterNativeChoreographerForRefreshRateCallbacks() { synchronized (mLock) { mDispatchNativeCallbacks = false; + updateCallbackIfNeededLocked(); } } } diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 385ad2d3577f..56f81423db4e 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -58,7 +58,7 @@ import java.util.List; public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants { private static final String TAG = "FaceManager"; - private static final boolean DEBUG = true; + private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; @@ -207,13 +207,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan throw new IllegalArgumentException("Must supply an authentication callback"); } - if (cancel != null) { - if (cancel.isCanceled()) { - Slog.w(TAG, "authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); - } + if (cancel != null && cancel.isCanceled()) { + Slog.w(TAG, "authentication already canceled"); + return; } if (mService != null) { @@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; Trace.beginSection("FaceManager#authenticate"); - mService.authenticate(mToken, operationId, userId, mServiceReceiver, - mContext.getOpPackageName(), isKeyguardBypassEnabled); + final long authId = mService.authenticate(mToken, operationId, userId, + mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled); + if (cancel != null) { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + } } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); - if (callback != null) { - // Though this may not be a hardware issue, it will cause apps to give up or - // try again later. - callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, - getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */)); - } + // Though this may not be a hardware issue, it will cause apps to give up or + // try again later. + callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, + getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */)); } finally { Trace.endSection(); } @@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (cancel.isCanceled()) { Slog.w(TAG, "Detection already cancelled"); return; - } else { - cancel.setOnCancelListener(new OnFaceDetectionCancelListener()); } mFaceDetectionCallback = callback; try { - mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + final long authId = mService.detectFace( + mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); } @@ -726,23 +723,23 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } } - private void cancelAuthentication(CryptoObject cryptoObject) { + private void cancelAuthentication(long requestId) { if (mService != null) { try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } - private void cancelFaceDetect() { + private void cancelFaceDetect(long requestId) { if (mService == null) { return; } try { - mService.cancelFaceDetect(mToken, mContext.getOpPackageName()); + mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -794,9 +791,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan // This is used as a last resort in case a vendor string is missing // It should not happen for anything other than FACE_ERROR_VENDOR, but // warn and use the default if all else fails. - // TODO(b/196639965): update string Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); - return ""; + return context.getString( + com.android.internal.R.string.face_error_vendor_unknown); } /** @@ -1110,22 +1107,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } private class OnAuthenticationCancelListener implements OnCancelListener { - private final CryptoObject mCrypto; + private final long mAuthRequestId; - OnAuthenticationCancelListener(CryptoObject crypto) { - mCrypto = crypto; + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; } @Override public void onCancel() { - cancelAuthentication(mCrypto); + Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } private class OnFaceDetectionCancelListener implements OnCancelListener { + private final long mAuthRequestId; + + OnFaceDetectionCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelFaceDetect(); + Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId); + cancelFaceDetect(mAuthRequestId); } } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index db02a0ef2a10..e9198246dee3 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -44,34 +44,36 @@ interface IFaceService { // Retrieve static sensor properties for the specified sensor FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); - // Authenticate the given sessionId with a face - void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, + // Authenticate with a face. A requestId is returned that can be used to cancel this operation. + long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, String opPackageName, boolean isKeyguardBypassEnabled); // Uses the face hardware to detect for the presence of a face, without giving details - // about accept/reject/lockout. - void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); + // about accept/reject/lockout. A requestId is returned that can be used to cancel this + // operation. + long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be // called from BiometricService. The additional uid, pid, userId arguments should be determined // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). - void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, - int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication); + void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, + long operationId, int userId, IBiometricSensorReceiver sensorReceiver, + String opPackageName, long requestId, int cookie, + boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); - // Cancel face detection - void cancelFaceDetect(IBinder token, String opPackageName); + // Cancel face detection for the given requestId. + void cancelFaceDetect(IBinder token, String opPackageName, long requestId); // Same as above, with extra arguments. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId); // Start face enrollment void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 87d45b9de745..a3d595c23095 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -146,6 +146,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing private CryptoObject mCryptoObject; @Nullable private RemoveTracker mRemoveTracker; private Handler mHandler; + @Nullable private float[] mEnrollStageThresholds; /** * Retrieves a list of properties for all fingerprint sensors on the device. @@ -189,22 +190,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } private class OnAuthenticationCancelListener implements OnCancelListener { - private android.hardware.biometrics.CryptoObject mCrypto; + private final long mAuthRequestId; - public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { - mCrypto = crypto; + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; } @Override public void onCancel() { - cancelAuthentication(mCrypto); + Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } private class OnFingerprintDetectionCancelListener implements OnCancelListener { + private final long mAuthRequestId; + + OnFingerprintDetectionCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelFingerprintDetect(); + Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId); + cancelFingerprintDetect(mAuthRequestId); } } @@ -552,13 +561,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing throw new IllegalArgumentException("Must supply an authentication callback"); } - if (cancel != null) { - if (cancel.isCanceled()) { - Slog.w(TAG, "authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); - } + if (cancel != null && cancel.isCanceled()) { + Slog.w(TAG, "authentication already canceled"); + return; } if (mService != null) { @@ -567,8 +572,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing mAuthenticationCallback = callback; mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; - mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver, - mContext.getOpPackageName()); + final long authId = mService.authenticate(mToken, operationId, sensorId, userId, + mServiceReceiver, mContext.getOpPackageName()); + if (cancel != null) { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + } } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); // Though this may not be a hardware issue, it will cause apps to give up or try @@ -595,15 +603,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing if (cancel.isCanceled()) { Slog.w(TAG, "Detection already cancelled"); return; - } else { - cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener()); } mFingerprintDetectionCallback = callback; try { - mService.detectFingerprint(mToken, userId, mServiceReceiver, + final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); } @@ -843,26 +850,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing return hasEnrolledFingerprints(userId); } - /** - * Checks if the specified user has enrollments in any of the specified sensors. - * @hide - */ - @RequiresPermission(USE_BIOMETRIC_INTERNAL) - public boolean hasEnrolledTemplatesForAnySensor(int userId, - @NonNull List sensors) { - if (mService == null) { - Slog.w(TAG, "hasEnrolledTemplatesForAnySensor: no fingerprint service"); - return false; - } - - try { - return mService.hasEnrolledTemplatesForAnySensor(userId, sensors, - mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - /** * @hide */ @@ -1320,26 +1307,66 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } - private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) { + private void cancelAuthentication(long requestId) { if (mService != null) try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - private void cancelFingerprintDetect() { + private void cancelFingerprintDetect(long requestId) { if (mService == null) { return; } try { - mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName()); + mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** + * @hide + */ + public int getEnrollStageCount() { + if (mEnrollStageThresholds == null) { + mEnrollStageThresholds = createEnrollStageThresholds(mContext); + } + return mEnrollStageThresholds.length + 1; + } + + /** + * @hide + */ + public float getEnrollStageThreshold(int index) { + if (mEnrollStageThresholds == null) { + mEnrollStageThresholds = createEnrollStageThresholds(mContext); + } + + if (index < 0 || index > mEnrollStageThresholds.length) { + Slog.w(TAG, "Unsupported enroll stage index: " + index); + return index < 0 ? 0f : 1f; + } + + // The implicit threshold for the final stage is always 1. + return index == mEnrollStageThresholds.length ? 1f : mEnrollStageThresholds[index]; + } + + @NonNull + private static float[] createEnrollStageThresholds(@NonNull Context context) { + // TODO(b/200604947): Fetch this value from FingerprintService, rather than internal config + final String[] enrollStageThresholdStrings = context.getResources().getStringArray( + com.android.internal.R.array.config_udfps_enroll_stage_thresholds); + + final float[] enrollStageThresholds = new float[enrollStageThresholdStrings.length]; + for (int i = 0; i < enrollStageThresholds.length; i++) { + enrollStageThresholds[i] = Float.parseFloat(enrollStageThresholdStrings[i]); + } + return enrollStageThresholds; + } + /** * @hide */ @@ -1390,9 +1417,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing // This is used as a last resort in case a vendor string is missing // It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but // warn and use the default if all else fails. - // TODO(b/196639965): update string Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); - return ""; + return context.getString( + com.android.internal.R.string.fingerprint_error_vendor_unknown); } /** diff --git a/core/java/android/hardware/fingerprint/FingerprintStateListener.java b/core/java/android/hardware/fingerprint/FingerprintStateListener.java index 6e607a269cb2..cf914c5acd1a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintStateListener.java +++ b/core/java/android/hardware/fingerprint/FingerprintStateListener.java @@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener * Defines behavior in response to state update * @param newState new state of fingerprint sensor */ - public abstract void onStateChanged(@FingerprintStateListener.State int newState); + public void onStateChanged(@FingerprintStateListener.State int newState) {}; + + /** + * Invoked when enrollment state changes for the specified user + */ + public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {}; } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3979afe80d17..de94b2fbb5b5 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -48,15 +48,16 @@ interface IFingerprintService { // Retrieve static sensor properties for the specified sensor FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); - // Authenticate the given sessionId with a fingerprint. This is protected by - // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes - // through FingerprintManager now. - void authenticate(IBinder token, long operationId, int sensorId, int userId, + // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC + // permission. This is effectively deprecated, since it only comes through FingerprintManager + // now. A requestId is returned that can be used to cancel this operation. + long authenticate(IBinder token, long operationId, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName); // Uses the fingerprint hardware to detect for the presence of a finger, without giving details - // about accept/reject/lockout. - void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, + // about accept/reject/lockout. A requestId is returned that can be used to cancel this + // operation. + long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. @@ -65,21 +66,21 @@ interface IFingerprintService { // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - boolean allowBackgroundAuthentication); + IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, + int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); - // Cancel finger detection - void cancelFingerprintDetect(IBinder token, String opPackageName); + // Cancel finger detection for the given requestId. + void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId); // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // an additional uid, pid, userid. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId); // Start fingerprint enrollment void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, @@ -119,9 +120,6 @@ interface IFingerprintService { // Determine if a user has at least one enrolled fingerprint. boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName); - // Determine if a user has at least one enrolled fingerprint in any of the specified sensors - boolean hasEnrolledTemplatesForAnySensor(int userId, in List sensors, String opPackageName); - // Return the LockoutTracker status for the specified user int getLockoutModeForUser(int sensorId, int userId); diff --git a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl index 56dba7ea1d9a..1aa6fa197066 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl @@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint; */ oneway interface IFingerprintStateListener { void onStateChanged(int newState); + void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments); } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 881e0cfb58d7..74cb42db7858 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1749,12 +1749,12 @@ public class InputMethodService extends AbstractInputMethodService { if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) { return false; } - if ((mInputEditorInfo != null - && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) + if (mInputEditorInfo != null + && ((mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0 // If app window has portrait orientation, regardless of what display orientation // is, IME shouldn't use fullscreen-mode. || (mInputEditorInfo.internalImeOptions - & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) { + & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0)) { return false; } return true; diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index f48375246616..0f94cbef3886 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -270,6 +270,16 @@ public final class BatteryUsageStats implements Parcelable { return mUserBatteryConsumers; } + /** + * Returns the names of custom power components in order, so the first name in the array + * corresponds to the custom componentId + * {@link BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID}. + */ + @NonNull + public String[] getCustomPowerComponentNames() { + return mCustomPowerComponentNames; + } + /** * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s. */ diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 3d466a0bf007..c6466235e5d1 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -74,7 +74,7 @@ public final class BinderProxy implements IBinder { private static final int MAIN_INDEX_SIZE = 1 << LOG_MAIN_INDEX_SIZE; private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1; // Debuggable builds will throw an AssertionError if the number of map entries exceeds: - private static final int CRASH_AT_SIZE = 20_000; + private static final int CRASH_AT_SIZE = 25_000; /** * We next warn when we exceed this bucket size. diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index be21fea1d0df..1cceea30868c 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -17,6 +17,7 @@ package android.os; import android.app.Activity; +import android.app.GameManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -26,8 +27,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.AssetFileDescriptor; -import android.content.res.AssetManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -37,9 +36,6 @@ import dalvik.system.VMRuntime; import java.io.BufferedReader; import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; @@ -88,9 +84,6 @@ public class GraphicsEnvironment { private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*"; private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt"; - // ANGLE related properties. - private static final String ANGLE_RULES_FILE = "a4a_rules.json"; - private static final String ANGLE_TEMP_RULES = "debug.angle.rules"; private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID"; private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE = "android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE"; @@ -121,6 +114,7 @@ public class GraphicsEnvironment { private ClassLoader mClassLoader; private String mLibrarySearchPaths; private String mLibraryPermittedPaths; + private GameManager mGameManager; private int mAngleOptInIndex = -1; @@ -133,6 +127,8 @@ public class GraphicsEnvironment { final ApplicationInfo appInfoWithMetaData = getAppInfoWithMetadata(context, pm, packageName); + mGameManager = context.getSystemService(GameManager.class); + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers"); setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData); Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); @@ -150,6 +146,23 @@ public class GraphicsEnvironment { Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); } + /** + * Query to determine if the Game Mode has enabled ANGLE. + */ + private boolean isAngleEnabledByGameMode(Context context, String packageName) { + try { + final boolean gameModeEnabledAngle = + (mGameManager != null) && mGameManager.isAngleEnabled(packageName); + Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle); + return gameModeEnabledAngle; + } catch (SecurityException e) { + Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled " + + "for package: " + packageName); + } + + return false; + } + /** * Query to determine if ANGLE should be used */ @@ -164,21 +177,16 @@ public class GraphicsEnvironment { Log.v(TAG, "ANGLE Developer option for '" + packageName + "' " + "set to: '" + devOptIn + "'"); - // We only want to use ANGLE if the app is in the allowlist, or the developer has - // explicitly chosen something other than default driver. - // The allowlist will be generated by the ANGLE APK at both boot time and - // ANGLE update time. It will only include apps mentioned in the rules file. - final boolean allowed = checkAngleAllowlist(context, coreSettings, packageName); + // We only want to use ANGLE if the developer has explicitly chosen something other than + // default driver. final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE); - - if (allowed) { - Log.v(TAG, "ANGLE allowlist includes " + packageName); - } if (requested) { Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn); } - return allowed || requested; + final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName); + + return requested || gameModeEnabledAngle; } private int getVulkanVersion(PackageManager pm) { @@ -474,117 +482,6 @@ public class GraphicsEnvironment { return debugPackage; } - /** - * Attempt to setup ANGLE with a temporary rules file. - * True: Temporary rules file was loaded. - * False: Temporary rules file was *not* loaded. - */ - private boolean setupAngleWithTempRulesFile(Context context, - String packageName, - String paths, - String devOptIn) { - /** - * We only want to load a temp rules file for: - * - apps that are marked 'debuggable' in their manifest - * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for - * debugging (PR_SET_DUMPABLE). - */ - if (!isDebuggable()) { - Log.v(TAG, "Skipping loading temporary rules file"); - return false; - } - - final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES); - - if (TextUtils.isEmpty(angleTempRules)) { - Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty"); - return false; - } - - Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules); - - final File tempRulesFile = new File(angleTempRules); - if (tempRulesFile.exists()) { - Log.i(TAG, angleTempRules + " exists, loading file."); - try { - final FileInputStream stream = new FileInputStream(angleTempRules); - - try { - final FileDescriptor rulesFd = stream.getFD(); - final long rulesOffset = 0; - final long rulesLength = stream.getChannel().size(); - Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules); - - setAngleInfo(paths, packageName, devOptIn, null, - rulesFd, rulesOffset, rulesLength); - - stream.close(); - - // We successfully setup ANGLE, so return with good status - return true; - } catch (IOException e) { - Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Temp ANGLE rules file not found: " + e); - } catch (SecurityException e) { - Log.w(TAG, "Temp ANGLE rules file not accessible: " + e); - } - } - - return false; - } - - /** - * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK. - * True: APK rules file was loaded. - * False: APK rules file was *not* loaded. - */ - private boolean setupAngleRulesApk(String anglePkgName, - ApplicationInfo angleInfo, - PackageManager pm, - String packageName, - String paths, - String devOptIn, - String[] features) { - // Pass the rules file to loader for ANGLE decisions - try { - final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets(); - - try { - final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE); - - setAngleInfo(paths, packageName, devOptIn, features, assetsFd.getFileDescriptor(), - assetsFd.getStartOffset(), assetsFd.getLength()); - - assetsFd.close(); - - return true; - } catch (IOException e) { - Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE - + " from '" + anglePkgName + "': " + e); - } - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e); - } - - return false; - } - - /** - * Pull ANGLE allowlist from GlobalSettings and compare against current package - */ - private boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) { - final ContentResolver contentResolver = context.getContentResolver(); - final List angleAllowlist = - getGlobalSettingsString(contentResolver, bundle, - Settings.Global.ANGLE_ALLOWLIST); - - if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist); - - return angleAllowlist.contains(packageName); - } - /** * Pass ANGLE details down to trigger enable logic * @@ -647,28 +544,21 @@ public class GraphicsEnvironment { if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths); - // If the user has set the developer option to something other than default, - // we need to call setupAngleRulesApk() with the package name and the developer - // option value (native/angle/other). Then later when we are actually trying to - // load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before - // and can confidently answer yes/no based on the previously set developer - // option value. - final String devOptIn = getDriverForPackage(context, bundle, packageName); - - if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) { - // We setup ANGLE with a temp rules file, so we're done here. - return true; + // We need to call setAngleInfo() with the package name and the developer option value + //(native/angle/other). Then later when we are actually trying to load a driver, + //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently + //answer yes/no based on the previously set developer option value. + final String devOptIn; + final String[] features = getAngleEglFeatures(context, bundle); + final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName); + if (gameModeEnabledAngle) { + devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE; + } else { + devOptIn = getDriverForPackage(context, bundle, packageName); } + setAngleInfo(paths, packageName, devOptIn, features); - String[] features = getAngleEglFeatures(context, bundle); - - if (setupAngleRulesApk( - anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) { - // ANGLE with rules is set up from the APK, hence return. - return true; - } - - return false; + return true; } /** @@ -956,7 +846,7 @@ public class GraphicsEnvironment { private static native void setGpuStats(String driverPackageName, String driverVersionName, long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion); private static native void setAngleInfo(String path, String appPackage, String devOptIn, - String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength); + String[] features); private static native boolean getShouldUseAngle(String packageName); private static native boolean setInjectLayersPrSetDumpable(); diff --git a/core/java/android/os/incremental/OWNERS b/core/java/android/os/incremental/OWNERS index 47eee6406206..363486905c93 100644 --- a/core/java/android/os/incremental/OWNERS +++ b/core/java/android/os/incremental/OWNERS @@ -1,6 +1,5 @@ # Bug component: 554432 alexbuy@google.com schfan@google.com -toddke@google.com zyy@google.com patb@google.com diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 54905ec6eaeb..8928a423c6cb 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -18,6 +18,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.os.IVold; import java.util.List; @@ -135,4 +136,19 @@ public abstract class StorageManagerInternal { * {@link VolumeInfo#isPrimary()} */ public abstract List getPrimaryVolumeIds(); + + /** + * Tells StorageManager that CE storage for this user has been prepared. + * + * @param userId userId for which CE storage has been prepared + */ + public abstract void markCeStoragePrepared(@UserIdInt int userId); + + /** + * Returns true when CE storage for this user has been prepared. + * + * When the user key is unlocked and CE storage has been prepared, + * it's ok to access and modify CE directories on volumes for this user. + */ + public abstract boolean isCeStoragePrepared(@UserIdInt int userId); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ac520e8b3dec..00abc759278f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2241,6 +2241,21 @@ public final class Settings { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS"; + /** + * Activity Action: Show screen that lets user configure wifi tethering. + *

+ * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + *

+ * Input: Nothing + *

+ * Output: Nothing + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_WIFI_TETHER_SETTING = + "com.android.settings.WIFI_TETHER_SETTINGS"; + /** * Broadcast to trigger notification of asking user to enable MMS. * Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}. @@ -11844,6 +11859,12 @@ public final class Settings { @Readable public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed"; + /** + * Whether UWB should be enabled. + * @hide + */ + public static final String UWB_ENABLED = "uwb_enabled"; + /** * Value to specify whether network quality scores and badging should be shown in the UI. * @@ -13669,13 +13690,6 @@ public final class Settings { public static final String ANGLE_GL_DRIVER_SELECTION_VALUES = "angle_gl_driver_selection_values"; - /** - * List of package names that should check ANGLE rules - * @hide - */ - @Readable - public static final String ANGLE_ALLOWLIST = "angle_allowlist"; - /** * Lists of ANGLE EGL features for debugging. * Each list of features is separated by a comma, each feature in each list is separated by @@ -14914,6 +14928,16 @@ public final class Settings { public static final String POWER_BUTTON_LONG_PRESS = "power_button_long_press"; + /** + * Override internal R.integer.config_longPressOnPowerDurationMs. It determines the length + * of power button press to be considered a long press in milliseconds. + * Used by PhoneWindowManager. + * @hide + */ + @Readable + public static final String POWER_BUTTON_LONG_PRESS_DURATION_MS = + "power_button_long_press_duration_ms"; + /** * Overrides internal R.integer.config_veryLongPressOnPowerBehavior. * Allowable values detailed in frameworks/base/core/res/res/values/config.xml. diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 8e4a68e52697..40041486f6a6 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -436,7 +436,7 @@ public class StatusBarNotification implements Parcelable { try { ApplicationInfo ai = context.getPackageManager() .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, - getUserId()); + getNormalizedUserId()); mContext = context.createApplicationContext(ai, Context.CONTEXT_RESTRICTED); } catch (PackageManager.NameNotFoundException e) { diff --git a/core/java/android/service/translation/ITranslationService.aidl b/core/java/android/service/translation/ITranslationService.aidl index e9dd2c3bd70b..4cc732ab5a30 100644 --- a/core/java/android/service/translation/ITranslationService.aidl +++ b/core/java/android/service/translation/ITranslationService.aidl @@ -24,7 +24,7 @@ import com.android.internal.os.IResultReceiver; /** * System-wide on-device translation service. * - *

Services requests to translate text between different languages. The primary use case for this + *

Services requests to translate data between different languages. The primary use case for this * service is automatic translation of text and web views, when the auto Translate feature is * enabled. * diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java index 93c006aff435..d454c393a7ce 100644 --- a/core/java/android/service/translation/TranslationService.java +++ b/core/java/android/service/translation/TranslationService.java @@ -48,6 +48,7 @@ import android.view.translation.TranslationManager; import android.view.translation.TranslationRequest; import android.view.translation.TranslationResponse; import android.view.translation.TranslationSpec; +import android.view.translation.Translator; import com.android.internal.os.IResultReceiver; @@ -81,7 +82,10 @@ public abstract class TranslationService extends Service { * android.R.styleable#TranslationService translation-service}> tag. * *

Here's an example of how to use it on {@code AndroidManifest.xml}: - * TODO: fill in doc example (check CCService/AFService). + *

 <translation-service
+     *     android:settingsActivity="foo.bar.SettingsActivity"
+     *     . . .
+     * />
*/ public static final String SERVICE_META_DATA = "android.translation_service"; @@ -148,7 +152,6 @@ public abstract class TranslationService extends Service { void onTranslationSuccess(@NonNull TranslationResponse response); /** - * TODO: implement javadoc * @removed use {@link #onTranslationSuccess} with an error response instead. */ @Deprecated @@ -225,7 +228,7 @@ public abstract class TranslationService extends Service { * should call back with {@code false}.

* * @param translationContext the {@link TranslationContext} of the session being created. - * @param sessionId the int id of the session. + * @param sessionId the id of the session. * @param callback {@link Consumer} to notify whether the session was successfully created. */ // TODO(b/176464808): the session id won't be unique cross client/server process. Need to find @@ -234,8 +237,6 @@ public abstract class TranslationService extends Service { int sessionId, @NonNull Consumer callback); /** - * TODO: fill in javadoc. - * * @removed use {@link #onCreateTranslationSession(TranslationContext, int, Consumer)} * instead. */ @@ -246,19 +247,16 @@ public abstract class TranslationService extends Service { } /** - * TODO: fill in javadoc. + * Called when a translation session is finished. * - * @param sessionId + *

The translation session is finished when the client calls {@link Translator#destroy()} on + * the corresponding translator. + * + * @param sessionId id of the session that finished. */ public abstract void onFinishTranslationSession(int sessionId); /** - * TODO: fill in javadoc. - * - * @param request - * @param sessionId - * @param callback - * @param cancellationSignal * @removed use * {@link #onTranslationRequest(TranslationRequest, int, CancellationSignal, Consumer)} instead. */ @@ -276,23 +274,29 @@ public abstract class TranslationService extends Service { * {@link TranslationRequest#FLAG_PARTIAL_RESPONSES} was set, the service may call * {@code callback.accept()} multiple times with partial responses.

* - * @param request - * @param sessionId - * @param callback - * @param cancellationSignal + * @param request The translation request containing the data to be translated. + * @param sessionId id of the session that sent the translation request. + * @param cancellationSignal A {@link CancellationSignal} that notifies when a client has + * cancelled the operation in progress. + * @param callback {@link Consumer} to pass back the translation response. */ public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId, @Nullable CancellationSignal cancellationSignal, @NonNull Consumer callback); /** - * TODO: fill in javadoc + * Called to request a set of {@link TranslationCapability}s that are supported by the service. + * + *

The set of translation capabilities are limited to those supporting the source and target + * {@link TranslationSpec.DataFormat}. e.g. Calling this with + * {@link TranslationSpec#DATA_FORMAT_TEXT} as source and target returns only capabilities that + * translates text to text.

* *

Must call {@code callback.accept} to pass back the set of translation capabilities.

* - * @param sourceFormat - * @param targetFormat - * @param callback + * @param sourceFormat data format restriction of the translation source spec. + * @param targetFormat data format restriction of the translation target spec. + * @param callback {@link Consumer} to pass back the set of translation capabilities. */ public abstract void onTranslationCapabilitiesRequest( @TranslationSpec.DataFormat int sourceFormat, diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index f4770727e31f..c9a0121936dc 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -96,6 +96,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -152,6 +153,7 @@ public abstract class WallpaperService extends Service { private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050; private static final int MSG_ZOOM = 10100; private static final int MSG_SCALE_PREVIEW = 10110; + private static final int MSG_REPORT_SHOWN = 10150; private static final List PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY); @@ -526,6 +528,39 @@ public abstract class WallpaperService extends Service { return false; } + /** + * This will be called in the end of {@link #updateSurface(boolean, boolean, boolean)}. + * If true is returned, the engine will not report shown until rendering finished is + * reported. Otherwise, the engine will report shown immediately right after redraw phase + * in {@link #updateSurface(boolean, boolean, boolean)}. + * + * @hide + */ + public boolean shouldWaitForEngineShown() { + return false; + } + + /** + * Reports the rendering is finished, stops waiting, then invokes + * {@link IWallpaperEngineWrapper#reportShown()}. + * + * @hide + */ + public void reportEngineShown(boolean waitForEngineShown) { + if (mIWallpaperEngine.mShownReported) return; + if (!waitForEngineShown) { + Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN); + mCaller.removeMessages(MSG_REPORT_SHOWN); + mCaller.sendMessage(message); + } else { + // if we are already waiting, no need to reset the timeout. + if (!mCaller.hasMessages(MSG_REPORT_SHOWN)) { + Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN); + mCaller.sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(5)); + } + } + } + /** * Control whether this wallpaper will receive raw touch events * from the window manager as the user interacts with the window @@ -930,7 +965,7 @@ public abstract class WallpaperService extends Service { void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) { if (mDestroyed) { - Log.w(TAG, "Ignoring updateSurface: destroyed"); + Log.w(TAG, "Ignoring updateSurface due to destroyed"); } boolean fixedSize = false; @@ -1197,7 +1232,6 @@ public abstract class WallpaperService extends Service { + this); onVisibilityChanged(false); } - } finally { mIsCreating = false; mSurfaceCreated = true; @@ -1207,7 +1241,7 @@ public abstract class WallpaperService extends Service { processLocalColors(mPendingXOffset, mPendingXOffsetStep); } reposition(); - mIWallpaperEngine.reportShown(); + reportEngineShown(shouldWaitForEngineShown()); } } catch (RemoteException ex) { } @@ -2048,6 +2082,8 @@ public abstract class WallpaperService extends Service { mShownReported = true; try { mConnection.engineShown(this); + Log.d(TAG, "Wallpaper has updated the surface:" + + mWallpaperManager.getWallpaperInfo()); } catch (RemoteException e) { Log.w(TAG, "Wallpaper host disappeared", e); return; @@ -2201,6 +2237,9 @@ public abstract class WallpaperService extends Service { // Connection went away, nothing to do in here. } } break; + case MSG_REPORT_SHOWN: { + reportShown(); + } break; default : Log.w(TAG, "Unknown message type " + message.what); } diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index 362ea8c87f7f..5e647a4531bc 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -115,7 +115,7 @@ public abstract class RecognitionService extends Service { @NonNull AttributionSource attributionSource) { try { if (mCurrentCallback == null) { - boolean preflightPermissionCheckPassed = checkPermissionForPreflight( + boolean preflightPermissionCheckPassed = checkPermissionForPreflightNotHardDenied( attributionSource); if (preflightPermissionCheckPassed) { if (DBG) { @@ -470,10 +470,11 @@ public abstract class RecognitionService extends Service { return mStartedDataDelivery; } - private boolean checkPermissionForPreflight(AttributionSource attributionSource) { - return PermissionChecker.checkPermissionForPreflight(RecognitionService.this, - Manifest.permission.RECORD_AUDIO, attributionSource) - == PermissionChecker.PERMISSION_GRANTED; + private boolean checkPermissionForPreflightNotHardDenied(AttributionSource attributionSource) { + int result = PermissionChecker.checkPermissionForPreflight(RecognitionService.this, + Manifest.permission.RECORD_AUDIO, attributionSource); + return result == PermissionChecker.PERMISSION_GRANTED + || result == PermissionChecker.PERMISSION_SOFT_DENIED; } void finishDataDelivery() { diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 1f11d10052fe..1a7ec7f99c95 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -782,7 +782,7 @@ public class TextLine { int spanStart = runStart; int spanLimit; - if (mSpanned == null) { + if (mSpanned == null || runStart == runLimit) { spanLimit = runLimit; } else { int target = after ? offset + 1 : offset; diff --git a/core/java/android/text/method/TranslationTransformationMethod.java b/core/java/android/text/method/TranslationTransformationMethod.java index 80387aa8d66d..43d186ee9d21 100644 --- a/core/java/android/text/method/TranslationTransformationMethod.java +++ b/core/java/android/text/method/TranslationTransformationMethod.java @@ -62,6 +62,13 @@ public class TranslationTransformationMethod implements TransformationMethod2 { return mOriginalTranslationMethod; } + /** + * Returns the {@link TextView}'s {@link ViewTranslationResponse}. + */ + public ViewTranslationResponse getViewTranslationResponse() { + return mTranslationResponse; + } + @Override public CharSequence getTransformation(CharSequence source, View view) { if (!mAllowLengthChanges) { diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 802163617b3b..a7ecf1f2a81d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -814,9 +814,10 @@ interface IWindowManager * @param displayId The display associated with the window context * @param options A bundle used to pass window-related options and choose the right DisplayArea * - * @return {@code true} if the WindowContext is attached to the DisplayArea successfully. + * @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is + * attached to the DisplayArea successfully. {@code null}, otherwise. */ - boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, + Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, in Bundle options); /** diff --git a/core/java/android/view/ScrollCaptureResponse.java b/core/java/android/view/ScrollCaptureResponse.java index 8808827b248a..758f9ab935cf 100644 --- a/core/java/android/view/ScrollCaptureResponse.java +++ b/core/java/android/view/ScrollCaptureResponse.java @@ -53,6 +53,10 @@ public class ScrollCaptureResponse implements Parcelable { @Nullable private String mWindowTitle = null; + /** The package which owns the window. */ + @Nullable + private String mPackageName = null; + /** Carries additional logging and debugging information when enabled. */ @NonNull @DataClass.PluralOf("message") @@ -77,7 +81,7 @@ public class ScrollCaptureResponse implements Parcelable { - // Code below generated by codegen v1.0.22. + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -97,6 +101,7 @@ public class ScrollCaptureResponse implements Parcelable { @Nullable Rect windowBounds, @Nullable Rect boundsInWindow, @Nullable String windowTitle, + @Nullable String packageName, @NonNull ArrayList messages) { this.mDescription = description; com.android.internal.util.AnnotationValidations.validate( @@ -105,6 +110,7 @@ public class ScrollCaptureResponse implements Parcelable { this.mWindowBounds = windowBounds; this.mBoundsInWindow = boundsInWindow; this.mWindowTitle = windowTitle; + this.mPackageName = packageName; this.mMessages = messages; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mMessages); @@ -152,6 +158,14 @@ public class ScrollCaptureResponse implements Parcelable { return mWindowTitle; } + /** + * The package name of the process the window is owned by. + */ + @DataClass.Generated.Member + public @Nullable String getPackageName() { + return mPackageName; + } + /** * Carries additional logging and debugging information when enabled. */ @@ -172,6 +186,7 @@ public class ScrollCaptureResponse implements Parcelable { "windowBounds = " + mWindowBounds + ", " + "boundsInWindow = " + mBoundsInWindow + ", " + "windowTitle = " + mWindowTitle + ", " + + "packageName = " + mPackageName + ", " + "messages = " + mMessages + " }"; } @@ -187,12 +202,14 @@ public class ScrollCaptureResponse implements Parcelable { if (mWindowBounds != null) flg |= 0x4; if (mBoundsInWindow != null) flg |= 0x8; if (mWindowTitle != null) flg |= 0x10; + if (mPackageName != null) flg |= 0x20; dest.writeByte(flg); dest.writeString(mDescription); if (mConnection != null) dest.writeStrongInterface(mConnection); if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags); if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags); if (mWindowTitle != null) dest.writeString(mWindowTitle); + if (mPackageName != null) dest.writeString(mPackageName); dest.writeStringList(mMessages); } @@ -213,6 +230,7 @@ public class ScrollCaptureResponse implements Parcelable { Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR); Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR); String windowTitle = (flg & 0x10) == 0 ? null : in.readString(); + String packageName = (flg & 0x20) == 0 ? null : in.readString(); ArrayList messages = new ArrayList<>(); in.readStringList(messages); @@ -223,6 +241,7 @@ public class ScrollCaptureResponse implements Parcelable { this.mWindowBounds = windowBounds; this.mBoundsInWindow = boundsInWindow; this.mWindowTitle = windowTitle; + this.mPackageName = packageName; this.mMessages = messages; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mMessages); @@ -256,6 +275,7 @@ public class ScrollCaptureResponse implements Parcelable { private @Nullable Rect mWindowBounds; private @Nullable Rect mBoundsInWindow; private @Nullable String mWindowTitle; + private @Nullable String mPackageName; private @NonNull ArrayList mMessages; private long mBuilderFieldsSet = 0L; @@ -318,13 +338,24 @@ public class ScrollCaptureResponse implements Parcelable { return this; } + /** + * The package name of the process the window is owned by. + */ + @DataClass.Generated.Member + public @NonNull Builder setPackageName(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mPackageName = value; + return this; + } + /** * Carries additional logging and debugging information when enabled. */ @DataClass.Generated.Member public @NonNull Builder setMessages(@NonNull ArrayList value) { checkNotUsed(); - mBuilderFieldsSet |= 0x20; + mBuilderFieldsSet |= 0x40; mMessages = value; return this; } @@ -340,7 +371,7 @@ public class ScrollCaptureResponse implements Parcelable { /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull ScrollCaptureResponse build() { checkNotUsed(); - mBuilderFieldsSet |= 0x40; // Mark builder used + mBuilderFieldsSet |= 0x80; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mDescription = ""; @@ -358,6 +389,9 @@ public class ScrollCaptureResponse implements Parcelable { mWindowTitle = null; } if ((mBuilderFieldsSet & 0x20) == 0) { + mPackageName = null; + } + if ((mBuilderFieldsSet & 0x40) == 0) { mMessages = new ArrayList<>(); } ScrollCaptureResponse o = new ScrollCaptureResponse( @@ -366,12 +400,13 @@ public class ScrollCaptureResponse implements Parcelable { mWindowBounds, mBoundsInWindow, mWindowTitle, + mPackageName, mMessages); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x40) != 0) { + if ((mBuilderFieldsSet & 0x80) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -379,10 +414,10 @@ public class ScrollCaptureResponse implements Parcelable { } @DataClass.Generated( - time = 1614833185795L, - codegenVersion = "1.0.22", + time = 1628630366187L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList mMessages\npublic boolean isConnected()\npublic void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)") + inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList mMessages\npublic boolean isConnected()\npublic void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index ff2d2eb3d334..fa7330fb84eb 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -98,6 +98,7 @@ public class Surface implements Parcelable { private static native int nativeSetFrameRate( long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy); + private static native void nativeDestroy(long nativeObject); public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -339,6 +340,9 @@ public class Surface implements Parcelable { */ @UnsupportedAppUsage public void destroy() { + if (mNativeObject != 0) { + nativeDestroy(mNativeObject); + } release(); } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index c1956e45653b..4b8b607de089 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -903,7 +903,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceAlpha = 1f; synchronized (mSurfaceControlLock) { - mSurface.release(); + mSurface.destroy(); if (mBlastBufferQueue != null) { mBlastBufferQueue.destroy(); mBlastBufferQueue = null; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f4223fb467f5..cf12955787b1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20830,13 +20830,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; } + notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); + mAttachInfo = null; if (mOverlay != null) { mOverlay.getOverlayView().dispatchDetachedFromWindow(); } notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3550a31f9038..0ecd76f82a8a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2836,8 +2836,13 @@ public final class ViewRootImpl implements ViewParent, } } + final boolean surfaceControlChanged = + (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) + == RELAYOUT_RES_SURFACE_CHANGED; + if (mSurfaceControl.isValid()) { - updateOpacity(mWindowAttributes, dragResizing); + updateOpacity(mWindowAttributes, dragResizing, + surfaceControlChanged /*forceUpdate */); } if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() @@ -2872,9 +2877,7 @@ public final class ViewRootImpl implements ViewParent, // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new // SurfaceControl. surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId() - || (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) - == RELAYOUT_RES_SURFACE_CHANGED) - && mSurface.isValid(); + || surfaceControlChanged) && mSurface.isValid(); if (surfaceReplaced) { mSurfaceSequenceId++; } @@ -7824,7 +7827,8 @@ public final class ViewRootImpl implements ViewParent, return relayoutResult; } - private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing) { + private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing, + boolean forceUpdate) { boolean opaque = false; if (!PixelFormat.formatHasAlpha(params.format) @@ -7840,7 +7844,7 @@ public final class ViewRootImpl implements ViewParent, opaque = true; } - if (mIsSurfaceOpaque == opaque) { + if (!forceUpdate && mIsSurfaceOpaque == opaque) { return; } @@ -9493,6 +9497,7 @@ public final class ViewRootImpl implements ViewParent, ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder(); response.setWindowTitle(getTitle().toString()); + response.setPackageName(mContext.getPackageName()); StringWriter writer = new StringWriter(); IndentingPrintWriter pw = new IndentingPrintWriter(writer); diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java index ec55a0273999..3365c70b5b34 100644 --- a/core/java/android/view/animation/TranslateAnimation.java +++ b/core/java/android/view/animation/TranslateAnimation.java @@ -57,6 +57,9 @@ public class TranslateAnimation extends Animation { /** @hide */ protected float mToYDelta; + private int mWidth; + private int mParentWidth; + /** * Constructor used when a TranslateAnimation is loaded from a resource. * @@ -179,5 +182,60 @@ public class TranslateAnimation extends Animation { mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth); mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight); mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight); + + mWidth = width; + mParentWidth = parentWidth; + } + + /** + * Checks whether or not the translation is exclusively an x axis translation. + * + * @hide + */ + public boolean isXAxisTransition() { + return mFromXDelta - mToXDelta != 0 && mFromYDelta - mToYDelta == 0; + } + + /** + * Checks whether or not the translation is a full width x axis slide in or out translation. + * + * @hide + */ + public boolean isFullWidthTranslate() { + boolean isXAxisSlideTransition = + isSlideInLeft() || isSlideOutRight() || isSlideInRight() || isSlideOutLeft(); + return mWidth == mParentWidth && isXAxisSlideTransition; + } + + private boolean isSlideInLeft() { + boolean startsOutOfParentOnLeft = mFromXDelta <= -mWidth; + return startsOutOfParentOnLeft && endsXEnclosedWithinParent(); + } + + private boolean isSlideOutRight() { + boolean endOutOfParentOnRight = mToXDelta >= mParentWidth; + return startsXEnclosedWithinParent() && endOutOfParentOnRight; + } + + private boolean isSlideInRight() { + boolean startsOutOfParentOnRight = mFromXDelta >= mParentWidth; + return startsOutOfParentOnRight && endsXEnclosedWithinParent(); + } + + private boolean isSlideOutLeft() { + boolean endOutOfParentOnLeft = mToXDelta <= -mWidth; + return startsXEnclosedWithinParent() && endOutOfParentOnLeft; + } + + private boolean endsXEnclosedWithinParent() { + return mWidth <= mParentWidth + && mToXDelta + mWidth <= mParentWidth + && mToXDelta >= 0; + } + + private boolean startsXEnclosedWithinParent() { + return mWidth <= mParentWidth + && mFromXDelta + mWidth <= mParentWidth + && mFromXDelta >= 0; } } diff --git a/core/java/android/view/translation/TranslationCapability.java b/core/java/android/view/translation/TranslationCapability.java index 65b749add1b2..b7e13dda9ff6 100644 --- a/core/java/android/view/translation/TranslationCapability.java +++ b/core/java/android/view/translation/TranslationCapability.java @@ -40,15 +40,18 @@ import java.util.function.Consumer; public final class TranslationCapability implements Parcelable { /** - * TODO: fill in javadoc + * The translation service supports translation between the source and target specs, and it is + * ready to be downloaded onto the device. */ public static final @ModelState int STATE_AVAILABLE_TO_DOWNLOAD = 1; /** - * TODO: fill in javadoc + * The translation service supports translation between the source and target specs, and it is + * being downloaded onto the device currently. */ public static final @ModelState int STATE_DOWNLOADING = 2; /** - * TODO: fill in javadoc + * The translation service supports translation between the source and target specs, and it is + * downloaded and ready to use on device. */ public static final @ModelState int STATE_ON_DEVICE = 3; /** @@ -305,7 +308,7 @@ public final class TranslationCapability implements Parcelable { }; @DataClass.Generated( - time = 1624307114468L, + time = 1629158466039L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/translation/TranslationCapability.java", inputSignatures = "public static final @android.view.translation.TranslationCapability.ModelState int STATE_AVAILABLE_TO_DOWNLOAD\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_DOWNLOADING\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_ON_DEVICE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_NOT_AVAILABLE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_REMOVED_AND_AVAILABLE\nprivate final @android.view.translation.TranslationCapability.ModelState int mState\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mTargetSpec\nprivate final boolean mUiTranslationEnabled\nprivate final @android.view.translation.TranslationContext.TranslationFlag int mSupportedTranslationFlags\nclass TranslationCapability extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstDefs=true, genToString=true, genConstructor=false)") diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java index df4836ebde46..0d41851ca704 100644 --- a/core/java/android/view/translation/TranslationRequest.java +++ b/core/java/android/view/translation/TranslationRequest.java @@ -39,12 +39,16 @@ public final class TranslationRequest implements Parcelable { public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1; /** * Indicates this request wants to receive the dictionary result. - * TODO: describe the structure of the result. + * + *

See {@link TranslationResponseValue#EXTRA_DEFINITIONS} for more detail on the structure + * of the returned data. */ public static final @RequestFlags int FLAG_DICTIONARY_RESULT = 0x2; /** * Indicates this request wants to receive the transliteration result. - * TODO: describe the structure of the result. + * + *

This returns a CharSequence representation of the transliteration of the translated text. + * See {@link TranslationResponseValue#getTransliteration()}. */ public static final @RequestFlags int FLAG_TRANSLITERATION_RESULT = 0x4; /** @@ -327,7 +331,8 @@ public final class TranslationRequest implements Parcelable { return this; } - /** @see #setTranslationRequestValues + /** + * @see #setTranslationRequestValues * @removed */ @DataClass.Generated.Member @@ -352,7 +357,8 @@ public final class TranslationRequest implements Parcelable { return this; } - /** @see #setViewTranslationRequests + /** + * @see #setViewTranslationRequests * @removed */ @DataClass.Generated.Member @@ -394,7 +400,7 @@ public final class TranslationRequest implements Parcelable { } @DataClass.Generated( - time = 1620429997487L, + time = 1629159107226L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java", inputSignatures = "public static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_DICTIONARY_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLITERATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_PARTIAL_RESPONSES\nprivate final @android.view.translation.TranslationRequest.RequestFlags int mFlags\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.List mTranslationRequestValues\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"viewTranslationRequest\") java.util.List mViewTranslationRequests\nprivate static int defaultFlags()\nprivate static java.util.List defaultTranslationRequestValues()\nprivate static java.util.List defaultViewTranslationRequests()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addTranslationRequestValue(android.view.translation.TranslationRequestValue)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addViewTranslationRequest(android.view.translation.ViewTranslationRequest)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genBuilder=true)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addTranslationRequestValue(android.view.translation.TranslationRequestValue)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addViewTranslationRequest(android.view.translation.ViewTranslationRequest)\nclass BaseBuilder extends java.lang.Object implements []") diff --git a/core/java/android/view/translation/TranslationResponseValue.java b/core/java/android/view/translation/TranslationResponseValue.java index a24dbc3ae4f8..9dff2d56322b 100644 --- a/core/java/android/view/translation/TranslationResponseValue.java +++ b/core/java/android/view/translation/TranslationResponseValue.java @@ -93,9 +93,11 @@ public final class TranslationResponseValue implements Parcelable { @NonNull private final Bundle mExtras; + // TODO: Add example of transliteration. /** * The transliteration result of the translated text. - * TODO: Describe the result structure. + * + *

This returns a CharSequence representation of the transliteration of the translated text. */ @Nullable private final CharSequence mTransliteration; @@ -223,7 +225,8 @@ public final class TranslationResponseValue implements Parcelable { /** * The transliteration result of the translated text. - * TODO: Describe the result structure. + * + *

This returns a CharSequence representation of the transliteration of the translated text. */ @DataClass.Generated.Member public @Nullable CharSequence getTransliteration() { @@ -407,7 +410,8 @@ public final class TranslationResponseValue implements Parcelable { /** * The transliteration result of the translated text. - * TODO: Describe the result structure. + * + *

This returns a CharSequence representation of the transliteration of the translated text. */ @DataClass.Generated.Member public @NonNull Builder setTransliteration(@NonNull CharSequence value) { @@ -448,7 +452,7 @@ public final class TranslationResponseValue implements Parcelable { } @DataClass.Generated( - time = 1622133051937L, + time = 1631057245846L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java", inputSignatures = "public static final int STATUS_SUCCESS\npublic static final int STATUS_ERROR\npublic static final java.lang.String EXTRA_DEFINITIONS\nprivate final @android.view.translation.TranslationResponseValue.Status int mStatusCode\nprivate final @android.annotation.Nullable java.lang.CharSequence mText\nprivate final @android.annotation.NonNull android.os.Bundle mExtras\nprivate final @android.annotation.Nullable java.lang.CharSequence mTransliteration\npublic static @android.annotation.NonNull android.view.translation.TranslationResponseValue forError()\nprivate static java.lang.CharSequence defaultText()\nprivate static android.os.Bundle defaultExtras()\nprivate boolean extrasEquals(android.os.Bundle)\nprivate static java.lang.CharSequence defaultTransliteration()\nclass TranslationResponseValue extends java.lang.Object implements [android.os.Parcelable]\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)\nclass BaseBuilder extends java.lang.Object implements []") diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index a8335918cc84..d078c2cfbfd1 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -356,7 +356,11 @@ public class UiTranslationController { } for (int i = 0; i < translatedResult.size(); i++) { final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i)); - final View view = mViews.get(autofillId).get(); + final WeakReference viewRef = mViews.get(autofillId); + if (viewRef == null) { + continue; + } + final View view = viewRef.get(); if (view == null) { Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId + " may be gone."); @@ -416,22 +420,30 @@ public class UiTranslationController { Log.w(TAG, "No AutofillId is set in ViewTranslationResponse"); continue; } - final View view = mViews.get(autofillId).get(); + final WeakReference viewRef = mViews.get(autofillId); + if (viewRef == null) { + continue; + } + final View view = viewRef.get(); if (view == null) { Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId + " may be gone."); continue; } mActivity.runOnUiThread(() -> { + ViewTranslationCallback callback = view.getViewTranslationCallback(); if (view.getViewTranslationResponse() != null && view.getViewTranslationResponse().equals(response)) { - if (DEBUG) { - Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId - + ". Ignoring."); + if (callback instanceof TextViewTranslationCallback) { + if (((TextViewTranslationCallback) callback).isShowingTranslation()) { + if (DEBUG) { + Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId + + ". Ignoring."); + } + return; + } } - return; } - ViewTranslationCallback callback = view.getViewTranslationCallback(); if (callback == null) { if (view instanceof TextView) { // developer doesn't provide their override, we set the default TextView @@ -590,9 +602,8 @@ public class UiTranslationController { final View rootView = roots.get(rootNum).getView(); if (rootView instanceof ViewGroup) { findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds); - } else { - addViewIfNeeded(sourceViewIds, rootView); } + addViewIfNeeded(sourceViewIds, rootView); } } @@ -603,9 +614,8 @@ public class UiTranslationController { final View child = viewGroup.getChildAt(i); if (child instanceof ViewGroup) { findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds); - } else { - addViewIfNeeded(sourceViewIds, child); } + addViewIfNeeded(sourceViewIds, child); } } diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java index b9ed32ce248b..3012e9344a1b 100644 --- a/core/java/android/view/translation/UiTranslationManager.java +++ b/core/java/android/view/translation/UiTranslationManager.java @@ -33,6 +33,7 @@ import android.util.ArrayMap; import android.util.Log; import android.view.View; import android.view.autofill.AutofillId; +import android.widget.TextView; import com.android.internal.annotations.GuardedBy; @@ -42,11 +43,50 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.Consumer; -// TODO(b/178044703): Describe what UI Translation is. /** - * The {@link UiTranslationManager} class provides ways for apps to use the ui translation + *

The {@link UiTranslationManager} class provides ways for apps to use the ui translation * function in framework. + * + *

The UI translation provides ways for apps to support inline translation for the views. For + * example the system supports text translation for {@link TextView}. To support UI translation for + * your views, you should override the following methods to provide the content to be translated + * and deal with the translated result. Here is an example for {@link TextView}-like views: + * + *


+ * public class MyTextView extends View {
+ *     public MyTextView(...) {
+ *         // implements how to show the translated result in your View in
+ *         // ViewTranslationCallback and set it by setViewTranslationCallback()
+ *         setViewTranslationCallback(new MyViewTranslationCallback());
+ *     }
+ *
+ *     public void onCreateViewTranslationRequest(int[] supportedFormats,
+ *             Consumer requestsCollector) {
+ *        // collect the information that needs to be translated
+ *        ViewTranslationRequest.Builder requestBuilder =
+ *                     new ViewTranslationRequest.Builder(getAutofillId());
+ *        requestBuilder.setValue(ViewTranslationRequest.ID_TEXT,
+ *                         TranslationRequestValue.forText(etText()));
+ *        requestsCollector.accept(requestBuilder.build());
+ *     }
+ *
+ *     public void onProvideContentCaptureStructure(
+ *             ViewStructure structure, int flags) {
+ *         // set ViewTranslationResponse
+ *         super.onViewTranslationResponse(response);
+ *     }
+ * }
+ * 
+ * + *

If your view provides its own virtual hierarchy (for example, if it's a browser that draws the + * HTML using {@link android.graphics.Canvas} or native libraries in a different render process), + * you must override {@link View#onCreateVirtualViewTranslationRequests(long[], int[], Consumer)} to + * provide the content to be translated and implement + * {@link View#onVirtualViewTranslationResponses(android.util.LongSparseArray)} for the translated + * result. You also need to implement {@link android.view.translation.ViewTranslationCallback} to + * handle the translated information show or hide in your {@link View}. */ public final class UiTranslationManager { @@ -248,14 +288,14 @@ public final class UiTranslationManager { } } - // TODO(b/178044703): Fix the View API link when it becomes public. /** * Register for notifications of UI Translation state changes on the foreground activity. This * is available to the owning application itself and also the current input method. *

* The application whose UI is being translated can use this to customize the UI Translation * behavior in ways that aren't made easy by methods like - * View#onCreateTranslationRequest(). + * {@link View#onCreateViewTranslationRequest(int[], Consumer)}. + * *

* Input methods can use this to offer complementary features to UI Translation; for example, * enabling outgoing message translation when the system is translating incoming messages in a diff --git a/core/java/android/view/translation/ViewTranslationCallback.java b/core/java/android/view/translation/ViewTranslationCallback.java index 6efd621c4caa..66c028b48dc6 100644 --- a/core/java/android/view/translation/ViewTranslationCallback.java +++ b/core/java/android/view/translation/ViewTranslationCallback.java @@ -19,9 +19,17 @@ package android.view.translation; import android.annotation.NonNull; import android.annotation.UiThread; import android.view.View; +import android.view.contentcapture.ContentCaptureSession; /** - * Callback for handling the translated information show or hide in the {@link View}. + *

Callback for handling the translated information show or hide in the {@link View}. + * + *

When the platform intelligence starts translation of an app's ui, the system will call + * {@link View#dispatchCreateViewTranslationRequest} to collect the {@link ViewTranslationRequest}s + * for translation purpose by traversing the hierarchy then send to translation service. After + * receiving the {@link ViewTranslationResponse}, the system will call + * {@link ViewTranslationCallback#onShowTranslation(View)} to show the translated information for + * the {@link View}. */ @UiThread public interface ViewTranslationCallback { @@ -33,13 +41,24 @@ public interface ViewTranslationCallback { * method will not be called before {@link View#onViewTranslationResponse} or * {@link View#onVirtualViewTranslationResponses}. * + *

NOTE: It is possible the user changes text that causes a new + * {@link ViewTranslationResponse} returns to show the new translation. If you cache the + * {@link ViewTranslationResponse} here, you should remember to keep the cached value up + * to date. + * + *

NOTE: For TextView implementation, {@link ContentCaptureSession#notifyViewTextChanged} + * shouldn't be called with the translated text, simply calling setText() here will trigger the + * method. You should either override {@code View#onProvideContentCaptureStructure()} to report + * the original text instead of the translated text or use a different approach to display the + * translated text. + * * See {@link View#onViewTranslationResponse} for how to get the translated information. * * @return {@code true} if the View handles showing the translation. */ boolean onShowTranslation(@NonNull View view); /** - * Called when the user wants to show the original text instead of the translated text. This + * Called when user wants to view the original content instead of the translated content. This * method will not be called before {@link View#onViewTranslationResponse} or * {@link View#onViewTranslationResponse}. * @@ -47,7 +66,8 @@ public interface ViewTranslationCallback { */ boolean onHideTranslation(@NonNull View view); /** - * Called when the user finish the Ui translation and no longer to show the translated text. + * Called when the translation state is no longer needed. It should restore the original content + * and clear all saved states. * * @return {@code true} if the View handles clearing the translation. */ diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 91fc5a56d979..fe5eb085dc5c 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -739,6 +739,16 @@ public class RemoteViews implements Parcelable, Filter { return mContextForResources.getPackageName(); } + @Override + public UserHandle getUser() { + return mContextForResources.getUser(); + } + + @Override + public int getUserId() { + return mContextForResources.getUserId(); + } + @Override public boolean isRestricted() { // Override isRestricted and direct to resource's implementation. The isRestricted is diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java index 9d60009031f9..4a78f3ee6fac 100644 --- a/core/java/android/widget/TextViewTranslationCallback.java +++ b/core/java/android/widget/TextViewTranslationCallback.java @@ -64,13 +64,24 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { */ @Override public boolean onShowTranslation(@NonNull View view) { + if (mIsShowingTranslation) { + if (DEBUG) { + Log.d(TAG, view + " is already showing translated text."); + } + return false; + } ViewTranslationResponse response = view.getViewTranslationResponse(); if (response == null) { Log.e(TAG, "onShowTranslation() shouldn't be called before " + "onViewTranslationResponse()."); return false; } - if (mTranslationTransformation == null) { + // It is possible user changes text and new translation response returns, system should + // update the translation response to keep the result up to date. + // Because TextView.setTransformationMethod() will skip the same TransformationMethod + // instance, we should create a new one to let new translation can work. + if (mTranslationTransformation == null + || !response.equals(mTranslationTransformation.getViewTranslationResponse())) { TransformationMethod originalTranslationMethod = ((TextView) view).getTransformationMethod(); mTranslationTransformation = new TranslationTransformationMethod(response, @@ -147,7 +158,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { return true; } - boolean isShowingTranslation() { + public boolean isShowingTranslation() { return mIsShowingTranslation; } diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl index 8b8dba89ea67..69bc1b5f7763 100644 --- a/core/java/android/window/ITaskOrganizer.aidl +++ b/core/java/android/window/ITaskOrganizer.aidl @@ -88,4 +88,9 @@ oneway interface ITaskOrganizer { * user has pressed back on the root activity of a task controlled by the task organizer. */ void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo); + + /** + * Called when the IME has drawn on the organized task. + */ + void onImeDrawnOnTask(int taskId); } diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index c7c91cdd0941..d8723a821a22 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -144,6 +144,10 @@ public class TaskOrganizer extends WindowOrganizer { @BinderThread public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} + /** @hide */ + @BinderThread + public void onImeDrawnOnTask(int taskId) {} + /** * Creates a persistent root task in WM for a particular windowing-mode. * @param displayId The display to create the root task on. @@ -287,6 +291,11 @@ public class TaskOrganizer extends WindowOrganizer { public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) { mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info)); } + + @Override + public void onImeDrawnOnTask(int taskId) { + mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId)); + } }; private ITaskOrganizerController getController() { diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 901625b0732c..6d0a6bd559ae 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -26,7 +26,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Bundle; -import android.os.IBinder; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -67,7 +66,7 @@ public class WindowContext extends ContextWrapper { mType = type; mOptions = options; mWindowManager = createWindowContextWindowManager(this); - IBinder token = getWindowContextToken(); + WindowTokenClient token = (WindowTokenClient) getWindowContextToken(); mController = new WindowContextController(token); Reference.reachabilityFence(this); diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java index d84f571931fd..505b45008663 100644 --- a/core/java/android/window/WindowContextController.java +++ b/core/java/android/window/WindowContextController.java @@ -19,6 +19,7 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -46,7 +47,7 @@ public class WindowContextController { @VisibleForTesting public boolean mAttachedToDisplayArea; @NonNull - private final IBinder mToken; + private final WindowTokenClient mToken; /** * Window Context Controller constructor @@ -54,14 +55,13 @@ public class WindowContextController { * @param token The token used to attach to a window manager node. It is usually from * {@link Context#getWindowContextToken()}. */ - public WindowContextController(@NonNull IBinder token) { - mToken = token; - mWms = WindowManagerGlobal.getWindowManagerService(); + public WindowContextController(@NonNull WindowTokenClient token) { + this(token, WindowManagerGlobal.getWindowManagerService()); } /** Used for test only. DO NOT USE it in production code. */ @VisibleForTesting - public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) { + public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) { mToken = token; mWms = mockWms; } @@ -81,8 +81,14 @@ public class WindowContextController { + "a DisplayArea once."); } try { - mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId, - options); + final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type, + displayId, options); + if (configuration != null) { + mAttachedToDisplayArea = true; + // Send the DisplayArea's configuration to WindowContext directly instead of + // waiting for dispatching from WMS. + mToken.onConfigurationChanged(configuration, displayId); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 6abf5575d353..4dcd2e74a53f 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -24,6 +24,8 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.ref.WeakReference; /** @@ -33,7 +35,7 @@ import java.lang.ref.WeakReference; * {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}. * * @see WindowContext - * @see android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, Bundle) + * @see android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, Bundle) * * @hide */ @@ -50,8 +52,8 @@ public class WindowTokenClient extends IWindowToken.Stub { * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. *

This method must be called before invoking - * {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, - * Bundle, boolean)}.

+ * {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, + * Bundle)}.

* * @param context context to be attached * @throws IllegalStateException if attached context has already existed. @@ -63,6 +65,13 @@ public class WindowTokenClient extends IWindowToken.Stub { mContextRef = new WeakReference<>(context); } + /** + * Called when {@link Configuration} updates from the server side receive. + * + * @param newConfig the updated {@link Configuration} + * @param newDisplayId the updated {@link android.view.Display} ID + */ + @VisibleForTesting @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { final Context context = mContextRef.get(); diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java index 84354d90b5f3..ec224e50eb8d 100644 --- a/core/java/com/android/internal/app/SuspendedAppActivity.java +++ b/core/java/com/android/internal/app/SuspendedAppActivity.java @@ -72,17 +72,19 @@ public class SuspendedAppActivity extends AlertActivity private Resources mSuspendingAppResources; private SuspendDialogInfo mSuppliedDialogInfo; private Bundle mOptions; - private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() { + private BroadcastReceiver mSuspendModifiedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) { - final String[] unsuspended = intent.getStringArrayExtra( + if (Intent.ACTION_PACKAGES_SUSPENSION_CHANGED.equals(intent.getAction())) { + // Suspension conditions were modified, dismiss any related visible dialogs. + final String[] modified = intent.getStringArrayExtra( Intent.EXTRA_CHANGED_PACKAGE_LIST); - if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) { + if (ArrayUtils.contains(modified, mSuspendedPackage)) { if (!isFinishing()) { - Slog.w(TAG, "Package " + mSuspendedPackage - + " got unsuspended while the dialog was visible. Finishing."); + Slog.w(TAG, "Package " + mSuspendedPackage + " has modified" + + " suspension conditions while dialog was visible. Finishing."); SuspendedAppActivity.this.finish(); + // TODO (b/198201994): reload the suspend dialog to show most relevant info } } } @@ -245,15 +247,16 @@ public class SuspendedAppActivity extends AlertActivity setupAlert(); - final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED); - registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null, - null); + final IntentFilter suspendModifiedFilter = + new IntentFilter(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED); + registerReceiverAsUser(mSuspendModifiedReceiver, UserHandle.of(mUserId), + suspendModifiedFilter, null, null); } @Override protected void onDestroy() { super.onDestroy(); - unregisterReceiver(mUnsuspendReceiver); + unregisterReceiver(mSuspendModifiedReceiver); } private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) { diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java index ce75f45d0897..068b882eb4f7 100644 --- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java +++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java @@ -165,7 +165,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { // Now fetch app icon and raster with no badging even in work profile Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info) - .getIconBitmap(android.os.Process.myUserHandle()); + .getIconBitmap(mContext.getUser()); // Raster target drawable with appIcon as a badge SimpleIconFactory sif = SimpleIconFactory.obtain(mContext); diff --git a/core/java/com/android/internal/infra/OWNERS b/core/java/com/android/internal/infra/OWNERS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index 8e7fae7aa061..d12c870d2591 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -50,6 +50,7 @@ import com.android.internal.util.FrameworkStatsLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.TimeUnit; /** * A class that allows the app to get the frame metrics from HardwareRendererObserver. @@ -103,6 +104,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener private boolean mCancelled = false; private FrameTrackerListener mListener; private boolean mTracingStarted = false; + private Runnable mWaitForFinishTimedOut; private static class JankInfo { long frameVsyncId; @@ -263,10 +265,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener if (mListener != null) { mListener.onCujEvents(mSession, ACTION_SESSION_END); } + // We don't remove observer here, + // will remove it when all the frame metrics in this duration are called back. + // See onFrameMetricsAvailable for the logic of removing the observer. + // Waiting at most 10 seconds for all callbacks to finish. + mWaitForFinishTimedOut = () -> { + Log.e(TAG, "force finish cuj because of time out:" + mSession.getName()); + finish(mJankInfos.size() - 1); + }; + mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10)); } - // We don't remove observer here, - // will remove it when all the frame metrics in this duration are called back. - // See onFrameMetricsAvailable for the logic of removing the observer. } /** @@ -396,7 +404,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } private void finish(int indexOnOrAfterEnd) { - + mHandler.removeCallbacks(mWaitForFinishTimedOut); + mWaitForFinishTimedOut = null; mMetricsFinalized = true; // The tracing has been ended, remove the observer, see if need to trigger perfetto. @@ -481,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } } if (DEBUG) { - Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName() + Log.i(TAG, "finish: CUJ=" + mSession.getName() + " (" + mBeginVsyncId + "," + mEndVsyncId + ")" + " totalFrames=" + totalFramesCount + " missedAppFrames=" + missedAppFramesCount diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index aabcd7f82ac7..610cd7339001 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -103,7 +103,7 @@ public class InteractionJankMonitor { private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName(); private static final String DEFAULT_WORKER_NAME = TAG + "-Worker"; - private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L); + private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L); private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY = diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 630851d126cc..0f1c6f3a150a 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -707,6 +707,10 @@ public class BatteryStatsImpl extends BatteryStats { * Mapping isolated uids to the actual owning app uid. */ final SparseIntArray mIsolatedUids = new SparseIntArray(); + /** + * Internal reference count of isolated uids. + */ + final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); /** * The statistics we have collected organized by uids. @@ -3897,6 +3901,7 @@ public class BatteryStatsImpl extends BatteryStats { public void addIsolatedUidLocked(int isolatedUid, int appUid, long elapsedRealtimeMs, long uptimeMs) { mIsolatedUids.put(isolatedUid, appUid); + mIsolatedUidRefCounts.put(isolatedUid, 1); final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs); u.addIsolatedUid(isolatedUid); } @@ -3915,19 +3920,51 @@ public class BatteryStatsImpl extends BatteryStats { } /** - * This should only be called after the cpu times have been read. + * Isolated uid should only be removed after all wakelocks associated with the uid are stopped + * and the cpu time-in-state has been read one last time for the uid. + * * @see #scheduleRemoveIsolatedUidLocked(int, int) + * + * @return true if the isolated uid is actually removed. */ @GuardedBy("this") - public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) { + public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, + long uptimeMs) { + final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1; + if (refCount > 0) { + // Isolated uid is still being tracked + mIsolatedUidRefCounts.put(isolatedUid, refCount); + return false; + } + final int idx = mIsolatedUids.indexOfKey(isolatedUid); if (idx >= 0) { final int ownerUid = mIsolatedUids.valueAt(idx); final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs); u.removeIsolatedUid(isolatedUid); mIsolatedUids.removeAt(idx); + mIsolatedUidRefCounts.delete(isolatedUid); + } else { + Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")"); } mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs)); + + return true; + } + + /** + * Increment the ref count for an isolated uid. + * call #maybeRemoveIsolatedUidLocked to decrement. + */ + public void incrementIsolatedUidRefCount(int uid) { + final int refCount = mIsolatedUidRefCounts.get(uid, 0); + if (refCount <= 0) { + // Uid is not mapped or referenced + Slog.w(TAG, + "Attempted to increment ref counted of untracked isolated uid (" + uid + ")"); + return; + } + mIsolatedUidRefCounts.put(uid, refCount + 1); } public int mapUid(int uid) { @@ -4287,7 +4324,7 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName, int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) { - uid = mapUid(uid); + final int mappedUid = mapUid(uid); if (type == WAKE_TYPE_PARTIAL) { // Only care about partial wake locks, since full wake locks // will be canceled when the user puts the screen to sleep. @@ -4297,9 +4334,9 @@ public class BatteryStatsImpl extends BatteryStats { } if (mRecordAllHistory) { if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, - uid, 0)) { + mappedUid, 0)) { addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, - HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid); + HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid); } } if (mWakeLockNesting == 0) { @@ -4308,7 +4345,7 @@ public class BatteryStatsImpl extends BatteryStats { + Integer.toHexString(mHistoryCur.states)); mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName; - mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; + mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid; mWakeLockImportant = !unimportantForLogging; addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } else if (!mWakeLockImportant && !unimportantForLogging @@ -4318,14 +4355,19 @@ public class BatteryStatsImpl extends BatteryStats { mHistoryLastWritten.wakelockTag = null; mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName; - mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; + mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid; addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } mWakeLockImportant = true; } mWakeLockNesting++; } - if (uid >= 0) { + if (mappedUid >= 0) { + if (mappedUid != uid) { + // Prevent the isolated uid mapping from being removed while the wakelock is + // being held. + incrementIsolatedUidRefCount(uid); + } if (mOnBatteryScreenOffTimeBase.isRunning()) { // We only update the cpu time when a wake lock is acquired if the screen is off. // If the screen is on, we don't distribute the power amongst partial wakelocks. @@ -4335,7 +4377,7 @@ public class BatteryStatsImpl extends BatteryStats { requestWakelockCpuUpdate(); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs) .noteStartWakeLocked(pid, name, type, elapsedRealtimeMs); if (wc != null) { @@ -4343,8 +4385,8 @@ public class BatteryStatsImpl extends BatteryStats { wc.getTags(), getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); } else { - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, - null, getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, + mappedUid, null, getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); } } @@ -4358,7 +4400,7 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName, int type, long elapsedRealtimeMs, long uptimeMs) { - uid = mapUid(uid); + final int mappedUid = mapUid(uid); if (type == WAKE_TYPE_PARTIAL) { mWakeLockNesting--; if (mRecordAllHistory) { @@ -4366,9 +4408,9 @@ public class BatteryStatsImpl extends BatteryStats { historyName = name; } if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, - uid, 0)) { + mappedUid, 0)) { addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, - HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid); + HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid); } } if (mWakeLockNesting == 0) { @@ -4380,7 +4422,7 @@ public class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } - if (uid >= 0) { + if (mappedUid >= 0) { if (mOnBatteryScreenOffTimeBase.isRunning()) { if (DEBUG_ENERGY_CPU) { Slog.d(TAG, "Updating cpu time because of -wake_lock"); @@ -4388,17 +4430,22 @@ public class BatteryStatsImpl extends BatteryStats { requestWakelockCpuUpdate(); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs) .noteStopWakeLocked(pid, name, type, elapsedRealtimeMs); if (wc != null) { FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); } else { - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, - null, getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, + mappedUid, null, getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); } + + if (mappedUid != uid) { + // Decrement the ref count for the isolated uid and delete the mapping if uneeded. + maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs); + } } } @@ -8571,7 +8618,7 @@ public class BatteryStatsImpl extends BatteryStats { * inactive so can be dropped. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public boolean reset(long uptimeUs, long realtimeUs) { + public boolean reset(long uptimeUs, long realtimeUs, int resetReason) { boolean active = false; mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs); @@ -8641,7 +8688,11 @@ public class BatteryStatsImpl extends BatteryStats { resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs); resetIfNotNull(mModemControllerActivity, false, realtimeUs); - MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats); + if (resetReason == RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE) { + mUidMeasuredEnergyStats = null; + } else { + MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats); + } resetIfNotNull(mUserCpuTime, false, realtimeUs); resetIfNotNull(mSystemCpuTime, false, realtimeUs); @@ -11324,7 +11375,7 @@ public class BatteryStatsImpl extends BatteryStats { mNumConnectivityChange = 0; for (int i=0; i" + ownerUid + " (ref count = " + refCount + ")"); + } + pw.println(); dumpConstantsLocked(pw); diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 00385793b62b..980aec196079 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -29,6 +29,7 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -234,8 +235,9 @@ public class BatteryUsageStatsProvider { final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; + final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames(); final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( - mStats.getCustomEnergyConsumerNames(), includePowerModels); + customEnergyConsumerNames, includePowerModels); if (mBatteryUsageStatsStore == null) { Log.e(TAG, "BatteryUsageStatsStore is unavailable"); return builder.build(); @@ -247,7 +249,14 @@ public class BatteryUsageStatsProvider { final BatteryUsageStats snapshot = mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp); if (snapshot != null) { - builder.add(snapshot); + if (Arrays.equals(snapshot.getCustomPowerComponentNames(), + customEnergyConsumerNames)) { + builder.add(snapshot); + } else { + Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different " + + "custom power components: " + + Arrays.toString(snapshot.getCustomPowerComponentNames())); + } } } } diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java index 9b51a8ef6410..bb307a0d29d8 100644 --- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java +++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java @@ -21,13 +21,18 @@ import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.UidBatteryConsumer; +import android.util.Slog; import android.util.SparseArray; +import java.util.Arrays; + /** * Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type * {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). */ public class CustomMeasuredPowerCalculator extends PowerCalculator { + private static final String TAG = "CustomMeasuredPowerCalc"; + public CustomMeasuredPowerCalculator(PowerProfile powerProfile) { } @@ -76,9 +81,9 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator { if (totalPowerMah == null) { newTotalPowerMah = new double[customMeasuredPowerMah.length]; } else if (totalPowerMah.length != customMeasuredPowerMah.length) { - newTotalPowerMah = new double[customMeasuredPowerMah.length]; - System.arraycopy(totalPowerMah, 0, newTotalPowerMah, 0, - customMeasuredPowerMah.length); + Slog.wtf(TAG, "Number of custom energy components is not the same for all apps: " + + totalPowerMah.length + ", " + customMeasuredPowerMah.length); + newTotalPowerMah = Arrays.copyOf(totalPowerMah, customMeasuredPowerMah.length); } else { newTotalPowerMah = totalPowerMah; } diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java index 776a70545df4..3915b0e01e7f 100644 --- a/core/java/com/android/internal/os/WifiPowerCalculator.java +++ b/core/java/com/android/internal/os/WifiPowerCalculator.java @@ -215,6 +215,9 @@ public class WifiPowerCalculator extends PowerCalculator { + "ms tx=" + txTime + "ms power=" + formatCharge( powerDurationAndTraffic.powerMah)); } + } else { + powerDurationAndTraffic.durationMs = 0; + powerDurationAndTraffic.powerMah = 0; } } else { final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000; diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java index b321ac08912b..a09c8236b47d 100644 --- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java +++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java @@ -124,7 +124,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - sendCloseSystemWindows(); mContext.startActivity(intent); } catch (ActivityNotFoundException e) { startCallActivity(); @@ -147,7 +146,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { dispatcher.performedLongPress(event); if (isUserSetupComplete()) { mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); // Broadcast an intent that the Camera button was longpressed Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); @@ -178,7 +176,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); getSearchManager().stopSearch(); mContext.startActivity(intent); // Only clear this if we successfully start the @@ -272,7 +269,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { @UnsupportedAppUsage void startCallActivity() { - sendCloseSystemWindows(); Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { @@ -319,10 +315,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { return mMediaSessionManager; } - void sendCloseSystemWindows() { - PhoneWindow.sendCloseSystemWindows(mContext, null); - } - private void handleVolumeKeyEvent(KeyEvent keyEvent) { getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent, AudioManager.USE_DEFAULT_STREAM_TYPE); diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 10f14b42ae42..ed6415d749a3 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -148,7 +148,7 @@ oneway interface IStatusBar */ void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, - String opPackageName, long operationId, int multiSensorConfig); + long operationId, String opPackageName, long requestId, int multiSensorConfig); /** * Used to notify the authentication dialog that a biometric has been authenticated. */ diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index e7d6d6cf8936..b3499db94c88 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -110,7 +110,8 @@ interface IStatusBarService // Used to show the authentication dialog (Biometrics, Device Credential) void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, int multiSensorConfig); + int userId, long operationId, String opPackageName, long requestId, + int multiSensorConfig); // Used to notify the authentication dialog that a biometric has been authenticated void onBiometricAuthenticated(); diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java index 8b3c1337c0c8..7a712e50e6a8 100644 --- a/core/java/com/android/internal/util/ContrastColorUtil.java +++ b/core/java/com/android/internal/util/ContrastColorUtil.java @@ -291,10 +291,10 @@ public class ContrastColorUtil { * Finds a suitable color such that there's enough contrast. * * @param color the color to start searching from. - * @param other the color to ensure contrast against. Assumed to be lighter than {@param color} - * @param findFg if true, we assume {@param color} is a foreground, otherwise a background. + * @param other the color to ensure contrast against. Assumed to be lighter than {@code color} + * @param findFg if true, we assume {@code color} is a foreground, otherwise a background. * @param minRatio the minimum contrast ratio required. - * @return a color with the same hue as {@param color}, potentially darkened to meet the + * @return a color with the same hue as {@code color}, potentially darkened to meet the * contrast ratio. */ public static int findContrastColor(int color, int other, boolean findFg, double minRatio) { @@ -331,7 +331,7 @@ public class ContrastColorUtil { * @param color the color to start searching from. * @param backgroundColor the color to ensure contrast against. * @param minRatio the minimum contrast ratio required. - * @return the same color as {@param color} with potentially modified alpha to meet contrast + * @return the same color as {@code color} with potentially modified alpha to meet contrast */ public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) { int fg = color; @@ -361,10 +361,10 @@ public class ContrastColorUtil { * Finds a suitable color such that there's enough contrast. * * @param color the color to start searching from. - * @param other the color to ensure contrast against. Assumed to be darker than {@param color} - * @param findFg if true, we assume {@param color} is a foreground, otherwise a background. + * @param other the color to ensure contrast against. Assumed to be darker than {@code color} + * @param findFg if true, we assume {@code color} is a foreground, otherwise a background. * @param minRatio the minimum contrast ratio required. - * @return a color with the same hue as {@param color}, potentially darkened to meet the + * @return a color with the same hue as {@code color}, potentially lightened to meet the * contrast ratio. */ public static int findContrastColorAgainstDark(int color, int other, boolean findFg, @@ -393,7 +393,8 @@ public class ContrastColorUtil { low = l; } } - return findFg ? fg : bg; + hsl[2] = high; + return ColorUtilsFromCompat.HSLToColor(hsl); } public static int ensureTextContrastOnBlack(int color) { @@ -452,7 +453,7 @@ public class ContrastColorUtil { } /** - * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT} + * Resolves {@code color} to an actual color if it is {@link Notification#COLOR_DEFAULT} */ public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) { if (color == Notification.COLOR_DEFAULT) { diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS index 100a605dc175..2b7f8b2749fd 100644 --- a/core/java/com/android/internal/util/OWNERS +++ b/core/java/com/android/internal/util/OWNERS @@ -4,4 +4,3 @@ per-file *Notification* = file:/services/core/java/com/android/server/notificati per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS per-file Protocol* = etancohen@google.com, lorenzo@google.com per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com -per-file DataClass* = eugenesusla@google.com \ No newline at end of file diff --git a/core/java/com/android/internal/util/function/pooled/OWNERS b/core/java/com/android/internal/util/function/pooled/OWNERS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 498505cd46ff..cd1bbb6bc6fe 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -17,6 +17,7 @@ package com.android.internal.widget; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; @@ -1271,6 +1272,14 @@ public class LockPatternUtils { } } + /** + * Whether the user is not allowed to set any credentials via PASSWORD_QUALITY_MANAGED. + */ + public boolean isCredentialsDisabledForUser(int userId) { + return getDevicePolicyManager().getPasswordQuality(/* admin= */ null, userId) + == PASSWORD_QUALITY_MANAGED; + } + /** * @see StrongAuthTracker#isTrustAllowedForUser */ diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java index 0c2d2a9bcf41..3191e23a9883 100644 --- a/core/java/com/android/internal/widget/NotificationActionListLayout.java +++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java @@ -53,6 +53,8 @@ public class NotificationActionListLayout extends LinearLayout { private int mEmphasizedHeight; private int mRegularHeight; @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start; + int mNumNotGoneChildren; + int mNumPriorityChildren; public NotificationActionListLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -76,15 +78,14 @@ public class NotificationActionListLayout extends LinearLayout { && ((EmphasizedNotificationButton) actionView).isPriority(); } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int N = getChildCount(); + private void countAndRebuildMeasureOrder() { + final int numChildren = getChildCount(); int textViews = 0; int otherViews = 0; - int notGoneChildren = 0; - int priorityChildren = 0; + mNumNotGoneChildren = 0; + mNumPriorityChildren = 0; - for (int i = 0; i < N; i++) { + for (int i = 0; i < numChildren; i++) { View c = getChildAt(i); if (c instanceof TextView) { textViews++; @@ -92,9 +93,9 @@ public class NotificationActionListLayout extends LinearLayout { otherViews++; } if (c.getVisibility() != GONE) { - notGoneChildren++; + mNumNotGoneChildren++; if (isPriority(c)) { - priorityChildren++; + mNumPriorityChildren++; } } } @@ -119,17 +120,20 @@ public class NotificationActionListLayout extends LinearLayout { if (needRebuild) { rebuildMeasureOrder(textViews, otherViews); } + } + private int measureAndGetUsedWidth(int widthMeasureSpec, int heightMeasureSpec, int innerWidth, + boolean collapsePriorityActions) { + final int numChildren = getChildCount(); final boolean constrained = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED; - - final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight; final int otherSize = mMeasureOrderOther.size(); int usedWidth = 0; + int maxPriorityWidth = 0; int measuredChildren = 0; int measuredPriorityChildren = 0; - for (int i = 0; i < N; i++) { + for (int i = 0; i < numChildren; i++) { // Measure shortest children first. To avoid measuring twice, we approximate by looking // at the text length. final boolean isPriority; @@ -154,12 +158,20 @@ public class NotificationActionListLayout extends LinearLayout { // measure in the order of (approx.) size, a large view can still take more than its // share if the others are small. int availableWidth = innerWidth - usedWidth; - int unmeasuredChildren = notGoneChildren - measuredChildren; + int unmeasuredChildren = mNumNotGoneChildren - measuredChildren; int maxWidthForChild = availableWidth / unmeasuredChildren; - if (isPriority) { + if (isPriority && collapsePriorityActions) { + // Collapsing the actions to just the width required to show the icon. + if (maxPriorityWidth == 0) { + maxPriorityWidth = getResources().getDimensionPixelSize( + R.dimen.notification_actions_collapsed_priority_width); + } + maxWidthForChild = maxPriorityWidth + lp.leftMargin + lp.rightMargin; + } else if (isPriority) { // Priority children get a larger maximum share of the total space: // maximum priority share = (nPriority + 1) / (MAX + 1) - int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren; + int unmeasuredPriorityChildren = mNumPriorityChildren + - measuredPriorityChildren; int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren; int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren / (Notification.MAX_ACTION_BUTTONS + 1); @@ -187,6 +199,19 @@ public class NotificationActionListLayout extends LinearLayout { } else { mExtraStartPadding = 0; } + return usedWidth; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + countAndRebuildMeasureOrder(); + final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight; + int usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth, + false /* collapsePriorityButtons */); + if (mNumPriorityChildren != 0 && usedWidth >= innerWidth) { + usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth, + true /* collapsePriorityButtons */); + } mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding; setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec), diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS index 554e27890476..81bad6a4ba69 100644 --- a/core/java/com/android/server/OWNERS +++ b/core/java/com/android/server/OWNERS @@ -1 +1 @@ -per-file SystemConfig.java = toddke@google.com,patb@google.com +per-file SystemConfig.java = patb@google.com diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 78787e52dbaa..eef705420173 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -3,7 +3,7 @@ per-file *Camera*,*camera* = cychen@google.com, epeev@google.com, etalvala@googl per-file *Camera*,*camera* = shuzhenwang@google.com, zhijunhe@google.com # Connectivity -per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com +per-file android_net_* = jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com # CPU per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index b40491a49b14..f44e829d49d7 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -50,8 +50,7 @@ void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName, } void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, - jstring devOptIn, jobjectArray featuresObj, jobject rulesFd, - jlong rulesOffset, jlong rulesLength) { + jstring devOptIn, jobjectArray featuresObj) { ScopedUtfChars pathChars(env, path); ScopedUtfChars appNameChars(env, appName); ScopedUtfChars devOptInChars(env, devOptIn); @@ -74,11 +73,8 @@ void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appNa } } - int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd); - android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(), - devOptInChars.c_str(), features, - rulesFd_native, rulesOffset, rulesLength); + devOptInChars.c_str(), features); } bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) { @@ -124,8 +120,7 @@ const JNINativeMethod g_methods[] = { {"setInjectLayersPrSetDumpable", "()Z", reinterpret_cast(setInjectLayersPrSetDumpable_native)}, {"setAngleInfo", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/io/" - "FileDescriptor;JJ)V", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V", reinterpret_cast(setAngleInfo_native)}, {"getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast(shouldUseAngle_native)}, diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 0957067de603..869b53df2837 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -449,6 +449,11 @@ static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jf int(changeFrameRateStrategy)); } +static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) { + sp surface(reinterpret_cast(nativeObject)); + surface->destroy(); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gSurfaceMethods[] = { @@ -477,6 +482,7 @@ static const JNINativeMethod gSurfaceMethods[] = { {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, {"nativeSetFrameRate", "(JFII)I", (void*)nativeSetFrameRate}, {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue}, + {"nativeDestroy", "(J)V", (void*)nativeDestroy}, }; int register_android_view_Surface(JNIEnv* env) diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 78650ed34813..931ef4478098 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -5,7 +5,6 @@ joeo@google.com singhtejinder@google.com yanmin@google.com yaochen@google.com -yro@google.com zhouwenjie@google.com # Frameworks @@ -13,7 +12,7 @@ ogunwale@google.com jjaggi@google.com kwekua@google.com roosa@google.com -per-file package_item_info.proto = toddke@google.com,patb@google.com +per-file package_item_info.proto = patb@google.com per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index c3d159659622..83e26f66fd62 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -771,6 +771,8 @@ message GlobalSettingsProto { optional SettingProto power_manager_constants = 93; reserved 94; // Used to be priv_app_oob_enabled + optional SettingProto power_button_long_press_duration_ms = 154 [ (android.privacy).dest = DEST_AUTOMATIC ]; + message PrepaidSetup { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -970,6 +972,7 @@ message GlobalSettingsProto { optional SettingProto usb_mass_storage_enabled = 127 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto use_google_mail = 128 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto use_open_wifi_package = 129 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto uwb_enabled = 155 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto vt_ims_enabled = 130 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto wait_for_debugger = 131 [ (android.privacy).dest = DEST_AUTOMATIC ]; @@ -1063,5 +1066,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 154; + // Next tag = 156; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d727a55615f2..f58f4e4be413 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -55,6 +55,7 @@ + diff --git a/core/res/OWNERS b/core/res/OWNERS index 165dcad896c9..e241dd6e3615 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -22,7 +22,6 @@ patb@google.com shanh@google.com svetoslavganov@android.com svetoslavganov@google.com -toddke@google.com tsuji@google.com yamasani@google.com diff --git a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml index 5add19bba51b..aa3800061bd3 100644 --- a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml +++ b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml @@ -18,19 +18,9 @@ --> - - + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> - - + android:shareInterpolator="false" + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> \ No newline at end of file diff --git a/core/res/res/anim-ldrtl/task_close_exit.xml b/core/res/res/anim-ldrtl/task_close_exit.xml index 71a44ae7d2fc..0887019ca608 100644 --- a/core/res/res/anim-ldrtl/task_close_exit.xml +++ b/core/res/res/anim-ldrtl/task_close_exit.xml @@ -15,19 +15,8 @@ --> - - + android:shareInterpolator="false" + android:hasRoundedCorners="true"> + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> - - - - - \ No newline at end of file + diff --git a/core/res/res/anim-ldrtl/task_open_enter.xml b/core/res/res/anim-ldrtl/task_open_enter.xml index 7815f7d661d0..52c74a6c4482 100644 --- a/core/res/res/anim-ldrtl/task_open_enter.xml +++ b/core/res/res/anim-ldrtl/task_open_enter.xml @@ -16,20 +16,9 @@ - - + android:shareInterpolator="false" + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - - \ No newline at end of file + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> + diff --git a/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml b/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml index 5fccd6df14a5..90ec0715f8b0 100644 --- a/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml +++ b/core/res/res/anim-ldrtl/task_open_enter_cross_profile_apps.xml @@ -16,20 +16,9 @@ --> - - + android:shareInterpolator="false" + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> @@ -75,4 +37,4 @@ android:toAlpha="1.0" android:startOffset="717" android:duration="200"/> - \ No newline at end of file + diff --git a/core/res/res/anim-ldrtl/task_open_exit.xml b/core/res/res/anim-ldrtl/task_open_exit.xml index 025e1bdc05c9..88cdcceae415 100644 --- a/core/res/res/anim-ldrtl/task_open_exit.xml +++ b/core/res/res/anim-ldrtl/task_open_exit.xml @@ -15,19 +15,8 @@ --> - - + android:shareInterpolator="false" + android:hasRoundedCorners="true"> + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> - - - - - \ No newline at end of file + diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml index 2cfeecf4685d..f6d7b7229677 100644 --- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml +++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml @@ -19,18 +19,8 @@ - - + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> - - + android:shareInterpolator="false" + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> \ No newline at end of file diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml index afc3256cb617..3a8dd934cd17 100644 --- a/core/res/res/anim/task_close_exit.xml +++ b/core/res/res/anim/task_close_exit.xml @@ -17,19 +17,8 @@ --> - - + android:shareInterpolator="false" + android:hasRoundedCorners="true"> + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> - - - - - \ No newline at end of file + diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml index 0aafc1c0b91c..3c934382bb75 100644 --- a/core/res/res/anim/task_open_enter.xml +++ b/core/res/res/anim/task_open_enter.xml @@ -15,23 +15,12 @@ ** limitations under the License. */ --> - - + + - - + android:shareInterpolator="false" + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> \ No newline at end of file diff --git a/core/res/res/anim/task_open_enter_cross_profile_apps.xml b/core/res/res/anim/task_open_enter_cross_profile_apps.xml index 702f7ba162aa..16249d15e1b7 100644 --- a/core/res/res/anim/task_open_enter_cross_profile_apps.xml +++ b/core/res/res/anim/task_open_enter_cross_profile_apps.xml @@ -18,20 +18,9 @@ --> - - + android:shareInterpolator="false" + android:zAdjustment="top" + android:hasRoundedCorners="true"> - - - - + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml index 691317d2e6e0..21fec7f694bf 100644 --- a/core/res/res/anim/task_open_exit.xml +++ b/core/res/res/anim/task_open_exit.xml @@ -17,19 +17,8 @@ --> - - + android:shareInterpolator="false" + android:hasRoundedCorners="true"> + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:startOffset="0" + android:duration="500"/> - - - - - \ No newline at end of file + diff --git a/core/res/res/color/overview_background.xml b/core/res/res/color/overview_background.xml new file mode 100644 index 000000000000..45c6c256d67a --- /dev/null +++ b/core/res/res/color/overview_background.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/core/res/res/color/overview_background_dark.xml b/core/res/res/color/overview_background_dark.xml new file mode 100644 index 000000000000..84f4fdff4e1a --- /dev/null +++ b/core/res/res/color/overview_background_dark.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/core/res/res/drawable/btn_notification_emphasized.xml b/core/res/res/drawable/btn_notification_emphasized.xml index 29c51f2a33c9..7c09fb889c48 100644 --- a/core/res/res/drawable/btn_notification_emphasized.xml +++ b/core/res/res/drawable/btn_notification_emphasized.xml @@ -24,9 +24,9 @@ android:insetBottom="@dimen/button_inset_vertical_material"> - diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml index 2e4578c39430..783fabe20a6d 100644 --- a/core/res/res/values-night/colors.xml +++ b/core/res/res/values-night/colors.xml @@ -33,4 +33,6 @@ #5DBA80 #8AB4F8 + + @color/overview_background_dark diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8496a478af97..fb7cddaf281a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -957,6 +957,20 @@ --> 5 + + 500 + + + + 250 + 350 + 500 + 650 + 750 + + @@ -4497,6 +4511,13 @@ If non-positive, then the refresh rate is unchanged even if thresholds are configured. --> 0 + + 0 + + + 0 + @@ -4556,6 +4577,13 @@ false + + + 0.25 + 0.5 + 0.75 + + diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index de7a1175b4a3..a666a5b4b796 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -58,6 +58,9 @@ 12dp + + 24dp 36dp + + 60dp + diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index be5063f3609a..0e09936bc251 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1730,6 +1730,8 @@ + + Something went wrong. Try again. Fingerprint icon @@ -1840,6 +1842,8 @@ + + Something went wrong. Try again. Face icon diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d06dafe9b3e7..8ed799111776 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -439,6 +439,8 @@ + + @@ -1742,6 +1744,7 @@ + @@ -2524,6 +2527,7 @@ + @@ -2563,6 +2567,7 @@ + @@ -2605,6 +2610,7 @@ + @@ -3184,6 +3190,7 @@ + @@ -3949,6 +3956,8 @@ + + @@ -4431,6 +4440,8 @@ + + diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index cd07d464ee65..34c1763b3286 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -16,9 +16,11 @@ package android.app; -import static androidx.core.graphics.ColorUtils.calculateContrast; +import static android.app.Notification.Builder.ensureColorSpanContrast; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsAtLeast; +import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsWithinRange; import static com.google.common.truth.Truth.assertThat; @@ -35,6 +37,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.content.LocusId; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -42,12 +45,21 @@ import android.graphics.drawable.Icon; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.text.style.TextAppearanceSpan; import android.widget.RemoteViews; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.R; +import com.android.internal.util.ContrastColorUtil; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -333,6 +345,163 @@ public class NotificationTest { assertNull(clone.getLocusId()); } + @Test + public void testBuilder_getFullLengthSpanColor_returnsNullForString() { + assertThat(Notification.Builder.getFullLengthSpanColor("String")).isNull(); + } + + @Test + public void testBuilder_getFullLengthSpanColor_returnsNullWithPartialSpan() { + CharSequence text = new SpannableStringBuilder() + .append("text with ") + .append("some red", new ForegroundColorSpan(Color.RED), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isNull(); + } + + @Test + public void testBuilder_getFullLengthSpanColor_worksWithSingleSpan() { + CharSequence text = new SpannableStringBuilder() + .append("text that is all red", new ForegroundColorSpan(Color.RED), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.RED); + } + + @Test + public void testBuilder_getFullLengthSpanColor_worksWithFullAndPartialSpans() { + Spannable text = new SpannableString("blue text with yellow and green"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.BLUE); + } + + @Test + public void testBuilder_getFullLengthSpanColor_worksWithTextAppearance() { + Spannable text = new SpannableString("title text with yellow and green"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, + R.style.TextAppearance_DeviceDefault_Notification_Title); + int expectedTextColor = textAppearanceSpan.getTextColor().getDefaultColor(); + text.setSpan(textAppearanceSpan, 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(expectedTextColor); + } + + @Test + public void testBuilder_ensureColorSpanContrast_removesAllFullLengthColorSpans() { + Spannable text = new SpannableString("blue text with yellow and green"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext, + R.style.TextAppearance_DeviceDefault_Notification_Title); + assertThat(taSpan.getTextColor()).isNotNull(); // it must be set to prove it is cleared. + text.setSpan(taSpan, 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable result = (Spannable) ensureColorSpanContrast(text, Color.BLACK); + Object[] spans = result.getSpans(0, result.length(), Object.class); + assertThat(spans).hasLength(3); + + assertThat(result.getSpanStart(spans[0])).isEqualTo(15); + assertThat(result.getSpanEnd(spans[0])).isEqualTo(21); + assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW); + + assertThat(result.getSpanStart(spans[1])).isEqualTo(0); + assertThat(result.getSpanEnd(spans[1])).isEqualTo(31); + assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span + assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily()); + assertThat(((TextAppearanceSpan) spans[1]).getTextColor()).isNull(); + + assertThat(result.getSpanStart(spans[2])).isEqualTo(26); + assertThat(result.getSpanEnd(spans[2])).isEqualTo(31); + assertThat(((ForegroundColorSpan) spans[2]).getForegroundColor()).isEqualTo(Color.GREEN); + } + + @Test + public void testBuilder_ensureColorSpanContrast_partialLength_adjusted() { + int background = 0xFFFF0101; // Slightly lighter red + CharSequence text = new SpannableStringBuilder() + .append("text with ") + .append("some red", new ForegroundColorSpan(Color.RED), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + CharSequence result = ensureColorSpanContrast(text, background); + + // ensure the span has been updated to have > 1.3:1 contrast ratio with fill color + Object[] spans = ((Spannable) result).getSpans(0, result.length(), Object.class); + assertThat(spans).hasLength(1); + int foregroundColor = ((ForegroundColorSpan) spans[0]).getForegroundColor(); + assertContrastIsWithinRange(foregroundColor, background, 3, 3.2); + } + + @Test + public void testBuilder_ensureColorSpanContrast_worksWithComplexInput() { + Spannable text = new SpannableString("blue text with yellow and green and cyan"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + // cyan TextAppearanceSpan + TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext, + R.style.TextAppearance_DeviceDefault_Notification_Title); + taSpan = new TextAppearanceSpan(taSpan.getFamily(), taSpan.getTextStyle(), + taSpan.getTextSize(), ColorStateList.valueOf(Color.CYAN), null); + text.setSpan(taSpan, 36, 40, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable result = (Spannable) ensureColorSpanContrast(text, Color.GRAY); + Object[] spans = result.getSpans(0, result.length(), Object.class); + assertThat(spans).hasLength(3); + + assertThat(result.getSpanStart(spans[0])).isEqualTo(15); + assertThat(result.getSpanEnd(spans[0])).isEqualTo(21); + assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW); + + assertThat(result.getSpanStart(spans[1])).isEqualTo(36); + assertThat(result.getSpanEnd(spans[1])).isEqualTo(40); + assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span + assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily()); + ColorStateList newCyanList = ((TextAppearanceSpan) spans[1]).getTextColor(); + assertThat(newCyanList).isNotNull(); + assertContrastIsWithinRange(newCyanList.getDefaultColor(), Color.GRAY, 3, 3.2); + + assertThat(result.getSpanStart(spans[2])).isEqualTo(26); + assertThat(result.getSpanEnd(spans[2])).isEqualTo(31); + int newGreen = ((ForegroundColorSpan) spans[2]).getForegroundColor(); + assertThat(newGreen).isNotEqualTo(Color.GREEN); + assertContrastIsWithinRange(newGreen, Color.GRAY, 3, 3.2); + } + + @Test + public void testBuilder_ensureButtonFillContrast_adjustsDarker() { + int background = Color.LTGRAY; + int foreground = Color.LTGRAY; + int result = Notification.Builder.ensureButtonFillContrast(foreground, background); + assertContrastIsWithinRange(result, background, 1.3, 1.5); + assertThat(ContrastColorUtil.calculateLuminance(result)) + .isLessThan(ContrastColorUtil.calculateLuminance(background)); + } + + @Test + public void testBuilder_ensureButtonFillContrast_adjustsLighter() { + int background = Color.DKGRAY; + int foreground = Color.DKGRAY; + int result = Notification.Builder.ensureButtonFillContrast(foreground, background); + assertContrastIsWithinRange(result, background, 1.3, 1.5); + assertThat(ContrastColorUtil.calculateLuminance(result)) + .isGreaterThan(ContrastColorUtil.calculateLuminance(background)); + } + @Test public void testColors_ensureColors_dayMode_producesValidPalette() { Notification.Colors c = new Notification.Colors(); @@ -399,6 +568,8 @@ public class NotificationTest { assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor()); assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor()); assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor()); + assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor()); + assertEquals(cDay.getOnAccentTextColor(), cNight.getOnAccentTextColor()); assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor()); assertEquals(cDay.getContrastColor(), cNight.getContrastColor()); assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha()); @@ -413,30 +584,26 @@ public class NotificationTest { assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); + assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); + assertThat(c.getOnAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getRippleAlpha()).isAtLeast(0x00); assertThat(c.getRippleAlpha()).isAtMost(0xff); - // Assert that various colors have sufficient contrast + // Assert that various colors have sufficient contrast with the background assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5); - // This accent color is only used for emphasized buttons + // These colors are only used for emphasized buttons; they do not need contrast assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1); - } + assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1); - private void assertContrastIsAtLeast(int foreground, int background, double minContrast) { - try { - assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast); - } catch (AssertionError e) { - throw new AssertionError( - String.format("Insufficient contrast: foreground=#%08x background=#%08x", - foreground, background), e); - } + // The text that is used within the accent color DOES need to have contrast + assertContrastIsAtLeast(c.getOnAccentTextColor(), c.getTertiaryAccentColor(), 4.5); } private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor, diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java index 22f6ec0b24b1..701e6194d4ee 100644 --- a/core/tests/coretests/src/android/graphics/FontListParserTest.java +++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java @@ -27,6 +27,7 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.fail; +import android.graphics.fonts.FontCustomizationParser; import android.graphics.fonts.FontStyle; import android.os.LocaleList; import android.text.FontConfig; @@ -46,6 +47,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) @@ -318,6 +320,52 @@ public final class FontListParserTest { } } + @Test + public void alias() throws Exception { + String xml = "" + + "" + + " " + + " test.ttf" + + " " + + " " + + " missing.ttf" + + " " + + " " + + ""; + FontConfig config = readFamilies(xml, true /* include non-existing font files */); + List aliases = config.getAliases(); + assertThat(aliases.size()).isEqualTo(1); + assertThat(aliases.get(0).getName()).isEqualTo("custom-alias"); + assertThat(aliases.get(0).getOriginal()).isEqualTo("sans-serif"); + } + + @Test + public void dropped_FamilyAlias() throws Exception { + String xml = "" + + "" + + " " + + " test.ttf" + + " " + + " " + + " missing.ttf" + + " " + + " " + + ""; + FontConfig config = readFamilies(xml, false /* exclude not existing file */); + assertThat(config.getAliases()).isEmpty(); + } + + private FontConfig readFamilies(String xml, boolean allowNonExisting) + throws IOException, XmlPullParserException { + ByteArrayInputStream buffer = new ByteArrayInputStream( + xml.getBytes(StandardCharsets.UTF_8)); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(buffer, "UTF-8"); + parser.nextTag(); + return FontListParser.readFamilies(parser, "", new FontCustomizationParser.Result(), null, + 0L /* last modified date */, 0 /* config version */, allowNonExisting); + } + private FontConfig.FontFamily readFamily(String xml) throws IOException, XmlPullParserException { ByteArrayInputStream buffer = new ByteArrayInputStream( diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index dfc9013e3c05..149f58f0a69b 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -32,6 +32,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -121,6 +122,46 @@ public class DisplayManagerGlobalTest { Mockito.verifyZeroInteractions(mListener); } + @Test + public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreNoOtherListeners() + throws RemoteException { + mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks(); + Mockito.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(ALL_DISPLAY_EVENTS)); + + mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks(); + Mockito.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L)); + + } + + @Test + public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreListeners() + throws RemoteException { + mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); + InOrder inOrder = Mockito.inOrder(mDisplayManager); + + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + + mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks(); + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), + eq(ALL_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + + mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks(); + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + + mDisplayManagerGlobal.unregisterDisplayListener(mListener); + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L)); + + } + private void waitForHandler() { mHandler.runWithScissors(() -> { }, 0); } diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java index a5a98a98f0be..109b7ab73d6f 100644 --- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java +++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java @@ -17,6 +17,8 @@ package android.service.notification; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNotSame; import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertFalse; @@ -51,6 +53,7 @@ public class StatusBarNotificationTest { private final Context mMockContext = mock(Context.class); @Mock + private Context mRealContext; private PackageManager mPm; private static final String PKG = "com.example.o"; @@ -75,6 +78,8 @@ public class StatusBarNotificationTest { InstrumentationRegistry.getContext().getResources()); when(mMockContext.getPackageManager()).thenReturn(mPm); when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); + + mRealContext = InstrumentationRegistry.getContext(); } @Test @@ -199,6 +204,19 @@ public class StatusBarNotificationTest { } + @Test + public void testGetPackageContext_worksWithUserAll() { + String pkg = "com.android.systemui"; + int uid = 1000; + Notification notification = getNotificationBuilder(GROUP_ID_1, CHANNEL_ID).build(); + StatusBarNotification sbn = new StatusBarNotification( + pkg, pkg, ID, TAG, uid, uid, notification, UserHandle.ALL, null, UID); + Context resultContext = sbn.getPackageContext(mRealContext); + assertNotNull(resultContext); + assertNotSame(mRealContext, resultContext); + assertEquals(pkg, resultContext.getPackageName()); + } + private StatusBarNotification getNotification(String pkg, String group, String channelId) { return getNotification(pkg, getNotificationBuilder(group, channelId)); } diff --git a/core/tests/coretests/src/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java index 020f4a06b892..073e46827bbb 100644 --- a/core/tests/coretests/src/android/window/WindowContextControllerTest.java +++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java @@ -23,11 +23,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.content.res.Configuration; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.IWindowManager; @@ -38,6 +40,8 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; /** * Tests for {@link WindowContextController} @@ -53,15 +57,18 @@ import org.junit.runner.RunWith; @Presubmit public class WindowContextControllerTest { private WindowContextController mController; + @Mock private IWindowManager mMockWms; + @Mock + private WindowTokenClient mMockToken; @Before public void setUp() throws Exception { - mMockWms = mock(IWindowManager.class); - mController = new WindowContextController(new Binder(), mMockWms); - - doReturn(true).when(mMockWms).attachWindowContextToDisplayArea(any(), anyInt(), - anyInt(), any()); + MockitoAnnotations.initMocks(this); + mController = new WindowContextController(mMockToken, mMockWms); + doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt()); + doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(), + anyInt(), anyInt(), any()); } @Test(expected = IllegalStateException.class) @@ -85,6 +92,7 @@ public class WindowContextControllerTest { null /* options */); assertThat(mController.mAttachedToDisplayArea).isTrue(); + verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY)); mController.detachIfNeeded(); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java index 464412f17722..d4799a8f5fd3 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java @@ -23,6 +23,8 @@ import android.app.ActivityManager; import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.Uid.Sensor; +import android.os.Process; +import android.os.UserHandle; import android.os.WorkSource; import android.util.SparseLongArray; import android.view.Display; @@ -53,6 +55,8 @@ import java.util.Map; public class BatteryStatsNoteTest extends TestCase { private static final int UID = 10500; + private static final int ISOLATED_APP_ID = Process.FIRST_ISOLATED_UID + 23; + private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID); private static final WorkSource WS = new WorkSource(UID); /** @@ -114,6 +118,88 @@ public class BatteryStatsNoteTest extends TestCase { assertEquals(120_000, bgTime); } + /** + * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid. + */ + @SmallTest + public void testNoteStartWakeLocked_isolatedUid() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + + int pid = 10; + String name = "name"; + String historyName = "historyName"; + + WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain(); + isolatedWorkChain.addNode(ISOLATED_UID, name); + + // Map ISOLATED_UID to UID. + bi.addIsolatedUidLocked(ISOLATED_UID, UID); + + bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); + bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL, false); + + clocks.realtime = clocks.uptime = 100; + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + + clocks.realtime = clocks.uptime = 220; + bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL); + + // ISOLATED_UID wakelock time should be attributed to UID. + BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID) + .getAggregatedPartialWakelockTimer(); + long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + assertEquals(220_000, actualTime); + assertEquals(120_000, bgTime); + } + + /** + * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid, with a race where the + * isolated uid is removed from batterystats before the wakelock has been stopped. + */ + @SmallTest + public void testNoteStartWakeLocked_isolatedUidRace() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + + int pid = 10; + String name = "name"; + String historyName = "historyName"; + + WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain(); + isolatedWorkChain.addNode(ISOLATED_UID, name); + + // Map ISOLATED_UID to UID. + bi.addIsolatedUidLocked(ISOLATED_UID, UID); + + bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); + bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL, false); + + clocks.realtime = clocks.uptime = 100; + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + + clocks.realtime = clocks.uptime = 150; + bi.maybeRemoveIsolatedUidLocked(ISOLATED_UID, clocks.realtime, clocks.uptime); + + clocks.realtime = clocks.uptime = 220; + bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL); + + // ISOLATED_UID wakelock time should be attributed to UID. + BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID) + .getAggregatedPartialWakelockTimer(); + long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + assertEquals(220_000, actualTime); + assertEquals(120_000, bgTime); + } + /** * Test BatteryStatsImpl.noteUidProcessStateLocked. @@ -506,7 +592,7 @@ public class BatteryStatsNoteTest extends TestCase { public void testUpdateDisplayMeasuredEnergyStatsLocked() { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); - bi.initMeasuredEnergyStats(); + bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); clocks.realtime = 0; int screen = Display.STATE_OFF; @@ -591,7 +677,7 @@ public class BatteryStatsNoteTest extends TestCase { public void testUpdateCustomMeasuredEnergyStatsLocked_neverCalled() { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); - bi.initMeasuredEnergyStats(); + bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); bi.setOnBatteryInternal(true); final int uid1 = 11500; @@ -605,7 +691,7 @@ public class BatteryStatsNoteTest extends TestCase { public void testUpdateCustomMeasuredEnergyStatsLocked() { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); - bi.initMeasuredEnergyStats(); + bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); final int bucketA = 0; // Custom bucket 0 final int bucketB = 1; // Custom bucket 1 diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java index b851f0ad3414..0135fe84909a 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java @@ -403,7 +403,7 @@ public class BatteryStatsSensorTest extends TestCase { assertNotNull(sensor.getSensorBackgroundTime()); // Reset the stats. Since the sensor is still running, we should still see the timer - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); sensor = uid.getSensorStats().get(SENSOR_ID); assertNotNull(sensor); @@ -413,7 +413,7 @@ public class BatteryStatsSensorTest extends TestCase { bi.noteStopSensorLocked(UID, SENSOR_ID); // Now the sensor timer has stopped so this reset should also take out the sensor. - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); sensor = uid.getSensorStats().get(SENSOR_ID); assertNull(sensor); @@ -465,7 +465,7 @@ public class BatteryStatsSensorTest extends TestCase { // Reset the stats. Since the sensor is still running, we should still see the timer // but still with 0 times. - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which)); assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime)); assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which)); @@ -504,7 +504,7 @@ public class BatteryStatsSensorTest extends TestCase { // Reset the stats. Since the sensor is still running, we should still see the timer // but with 0 times. - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which)); assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime)); assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which)); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java index 0147cdb186f3..74b6dbe76a16 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java @@ -18,6 +18,9 @@ package com.android.internal.os; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.app.ActivityManager; import android.content.Context; import android.os.BatteryConsumer; @@ -263,6 +266,39 @@ public class BatteryUsageStatsProviderTest { .of(180.0); } + @Test + public void testAggregateBatteryStats_incompatibleSnapshot() { + Context context = InstrumentationRegistry.getContext(); + MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); + batteryStats.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); + + BatteryUsageStatsStore batteryUsageStatsStore = mock(BatteryUsageStatsStore.class); + + when(batteryUsageStatsStore.listBatteryUsageStatsTimestamps()) + .thenReturn(new long[]{1000, 2000}); + + when(batteryUsageStatsStore.loadBatteryUsageStats(1000)).thenReturn( + new BatteryUsageStats.Builder(batteryStats.getCustomEnergyConsumerNames()) + .setStatsDuration(1234).build()); + + // Add a snapshot, with a different set of custom power components. It should + // be skipped by the aggregation. + when(batteryUsageStatsStore.loadBatteryUsageStats(2000)).thenReturn( + new BatteryUsageStats.Builder(new String[]{"different"}) + .setStatsDuration(4321).build()); + + BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, + batteryStats, batteryUsageStatsStore); + + BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder() + .aggregateSnapshots(0, 3000) + .build(); + final BatteryUsageStats stats = provider.getBatteryUsageStats(query); + assertThat(stats.getCustomPowerComponentNames()) + .isEqualTo(batteryStats.getCustomEnergyConsumerNames()); + assertThat(stats.getStatsDuration()).isEqualTo(1234); + } + private static class TestHandler extends Handler { TestHandler() { super(Looper.getMainLooper()); diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index 99d576d259ec..cee1a0352a7e 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -57,11 +57,10 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { this(new MockClocks()); } - public void initMeasuredEnergyStats() { + public void initMeasuredEnergyStats(String[] customBucketNames) { final boolean[] supportedStandardBuckets = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS]; Arrays.fill(supportedStandardBuckets, true); - final String[] customBucketNames = {"FOO", "BAR"}; mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames); } diff --git a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java new file mode 100644 index 000000000000..cfe660c77817 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 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.internal.util; + +import static androidx.core.graphics.ColorUtils.calculateContrast; + +import static com.google.common.truth.Truth.assertThat; + +import android.graphics.Color; + +import androidx.test.filters.SmallTest; + +import junit.framework.TestCase; + +public class ContrastColorUtilTest extends TestCase { + + @SmallTest + public void testEnsureTextContrastAgainstDark() { + int darkBg = 0xFF35302A; + + int blueContrastColor = ContrastColorUtil.ensureTextContrast(Color.BLUE, darkBg, true); + assertContrastIsWithinRange(blueContrastColor, darkBg, 4.5, 4.75); + + int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, darkBg, true); + assertContrastIsWithinRange(redContrastColor, darkBg, 4.5, 4.75); + + final int darkGreen = 0xff008800; + int greenContrastColor = ContrastColorUtil.ensureTextContrast(darkGreen, darkBg, true); + assertContrastIsWithinRange(greenContrastColor, darkBg, 4.5, 4.75); + + int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.DKGRAY, darkBg, true); + assertContrastIsWithinRange(grayContrastColor, darkBg, 4.5, 4.75); + + int selfContrastColor = ContrastColorUtil.ensureTextContrast(darkBg, darkBg, true); + assertContrastIsWithinRange(selfContrastColor, darkBg, 4.5, 4.75); + } + + @SmallTest + public void testEnsureTextContrastAgainstLight() { + int lightBg = 0xFFFFF8F2; + + final int lightBlue = 0xff8888ff; + int blueContrastColor = ContrastColorUtil.ensureTextContrast(lightBlue, lightBg, false); + assertContrastIsWithinRange(blueContrastColor, lightBg, 4.5, 4.75); + + int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, lightBg, false); + assertContrastIsWithinRange(redContrastColor, lightBg, 4.5, 4.75); + + int greenContrastColor = ContrastColorUtil.ensureTextContrast(Color.GREEN, lightBg, false); + assertContrastIsWithinRange(greenContrastColor, lightBg, 4.5, 4.75); + + int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.LTGRAY, lightBg, false); + assertContrastIsWithinRange(grayContrastColor, lightBg, 4.5, 4.75); + + int selfContrastColor = ContrastColorUtil.ensureTextContrast(lightBg, lightBg, false); + assertContrastIsWithinRange(selfContrastColor, lightBg, 4.5, 4.75); + } + + public static void assertContrastIsWithinRange(int foreground, int background, + double minContrast, double maxContrast) { + assertContrastIsAtLeast(foreground, background, minContrast); + assertContrastIsAtMost(foreground, background, maxContrast); + } + + public static void assertContrastIsAtLeast(int foreground, int background, double minContrast) { + try { + assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast); + } catch (AssertionError e) { + throw new AssertionError( + String.format("Insufficient contrast: foreground=#%08x background=#%08x", + foreground, background), e); + } + } + + public static void assertContrastIsAtMost(int foreground, int background, double maxContrast) { + try { + assertThat(calculateContrast(foreground, background)).isAtMost(maxContrast); + } catch (AssertionError e) { + throw new AssertionError( + String.format("Excessive contrast: foreground=#%08x background=#%08x", + foreground, background), e); + } + } + +} diff --git a/data/etc/OWNERS b/data/etc/OWNERS index ea23aba16d12..2c93d5abc155 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -8,8 +8,6 @@ jsharkey@google.com lorenzo@google.com svetoslavganov@android.com svetoslavganov@google.com -toddke@android.com -toddke@google.com patb@google.com yamasani@google.com diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml index 40dda6573ccc..eeb65ae8e129 100644 --- a/data/etc/car/com.google.android.car.kitchensink.xml +++ b/data/etc/car/com.google.android.car.kitchensink.xml @@ -48,6 +48,7 @@ + diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 93a336e7a408..96b33259e739 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -25,6 +25,7 @@ import android.graphics.fonts.FontVariationAxis; import android.os.Build; import android.os.LocaleList; import android.text.FontConfig; +import android.util.ArraySet; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; @@ -37,6 +38,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -120,7 +122,23 @@ public class FontListParser { } } - private static FontConfig readFamilies( + /** + * Parses the familyset tag in font.xml + * @param parser a XML pull parser + * @param fontDir A system font directory, e.g. "/system/fonts" + * @param customization A OEM font customization + * @param updatableFontMap A map of updated font files + * @param lastModifiedDate A date that the system font is updated. + * @param configVersion A version of system font config. + * @param allowNonExistingFile true if allowing non-existing font files during parsing fonts.xml + * @return result of fonts.xml + * + * @throws XmlPullParserException + * @throws IOException + * + * @hide + */ + public static FontConfig readFamilies( @NonNull XmlPullParser parser, @NonNull String fontDir, @NonNull FontCustomizationParser.Result customization, @@ -159,7 +177,24 @@ public class FontListParser { } families.addAll(oemNamedFamilies.values()); - return new FontConfig(families, aliases, lastModifiedDate, configVersion); + + // Filters aliases that point to non-existing families. + Set namedFamilies = new ArraySet<>(); + for (int i = 0; i < families.size(); ++i) { + String name = families.get(i).getName(); + if (name != null) { + namedFamilies.add(name); + } + } + List filtered = new ArrayList<>(); + for (int i = 0; i < aliases.size(); ++i) { + FontConfig.Alias alias = aliases.get(i); + if (namedFamilies.contains(alias.getOriginal())) { + filtered.add(alias); + } + } + + return new FontConfig(families, filtered, lastModifiedDate, configVersion); } private static boolean keepReading(XmlPullParser parser) diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 5b79d76dd6b9..9feb619b34e3 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -178,22 +178,8 @@ public class ImageFormat { *

Android YUV P010 format.

* * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane - * followed immediately by a Wx(H/2) CbCr plane. Each sample is - * represented by a 16-bit little-endian value, with the lower 6 bits set - * to zero. - * - *

This format assumes - *

    - *
  • an even height
  • - *
  • a vertical stride equal to the height
  • - *
- *

- * - *
   stride_in_bytes = stride * 2 
- *
   y_size = stride_in_bytes * height 
- *
   cbcr_size = stride_in_bytes * (height / 2) 
- *
   cb_offset = y_size 
- *
   cr_offset = cb_offset + 2 
+ * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit + * little-endian value, with the lower 6 bits set to zero. * *

For example, the {@link android.media.Image} object can provide data * in this format from a {@link android.hardware.camera2.CameraDevice} @@ -841,7 +827,7 @@ public class ImageFormat { case RAW_SENSOR: return 16; case YCBCR_P010: - return 20; + return 24; case RAW_DEPTH10: case RAW10: return 10; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index ba0ab6db1003..656bdff0c782 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -335,6 +335,13 @@ public class ShellTaskOrganizer extends TaskOrganizer implements } } + @Override + public void onImeDrawnOnTask(int taskId) { + if (mStartingWindow != null) { + mStartingWindow.onImeDrawnOnTask(taskId); + } + } + @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { synchronized (mLock) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index c0df06f2954f..ac97c8f80617 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -576,20 +576,17 @@ public class BubbleStackView extends FrameLayout mBubbleContainer.setActiveController(mStackAnimationController); hideFlyoutImmediate(); - if (!mPositioner.showingInTaskbar()) { - // Also, save the magnetized stack so we can dispatch touch events to it. - mMagnetizedObject = mStackAnimationController.getMagnetizedStack( - mMagneticTarget); - mMagnetizedObject.setMagnetListener(mStackMagnetListener); - } else { + if (mPositioner.showingInTaskbar()) { // In taskbar, the stack isn't draggable so we shouldn't dispatch touch events. mMagnetizedObject = null; + } else { + // Save the magnetized stack so we can dispatch touch events to it. + mMagnetizedObject = mStackAnimationController.getMagnetizedStack(); + mMagnetizedObject.clearAllTargets(); + mMagnetizedObject.addTarget(mMagneticTarget); + mMagnetizedObject.setMagnetListener(mStackMagnetListener); } - // Also, save the magnetized stack so we can dispatch touch events to it. - mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget); - mMagnetizedObject.setMagnetListener(mStackMagnetListener); - mIsDraggingStack = true; // Cancel animations to make the stack temporarily invisible, since we're now @@ -881,7 +878,6 @@ public class BubbleStackView extends FrameLayout mRelativeStackPositionBeforeRotation = null; } - setUpDismissView(); if (mIsExpanded) { // Re-draw bubble row and pointer for new orientation. beforeExpandedViewAnimation(); @@ -1043,10 +1039,9 @@ public class BubbleStackView extends FrameLayout contentResolver, "bubble_dismiss_radius", mBubbleSize * 2 /* default */); // Save the MagneticTarget instance for the newly set up view - we'll add this to the - // MagnetizedObjects. + // MagnetizedObjects when the dismiss view gets shown. mMagneticTarget = new MagnetizedObject.MagneticTarget( mDismissView.getCircle(), dismissRadius); - mBubbleContainer.bringToFront(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java index 0802fb59a008..636e1452aa9b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java @@ -1024,11 +1024,9 @@ public class StackAnimationController extends } /** - * Returns the {@link MagnetizedObject} instance for the bubble stack, with the provided - * {@link MagnetizedObject.MagneticTarget} added as a target. + * Returns the {@link MagnetizedObject} instance for the bubble stack. */ - public MagnetizedObject getMagnetizedStack( - MagnetizedObject.MagneticTarget target) { + public MagnetizedObject getMagnetizedStack() { if (mMagnetizedStack == null) { mMagnetizedStack = new MagnetizedObject( mLayout.getContext(), @@ -1053,7 +1051,6 @@ public class StackAnimationController extends loc[1] = (int) mStackPosition.y; } }; - mMagnetizedStack.addTarget(target); mMagnetizedStack.setHapticsEnabled(true); mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt index 9f6dd1f27b62..9e012598554b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt @@ -302,6 +302,13 @@ abstract class MagnetizedObject( associatedTargets.remove(target) } + /** + * Removes all associated targets from this object. + */ + fun clearAllTargets() { + associatedTargets.clear() + } + /** * Provide this method with all motion events that move the magnetized object. If the * location of the motion events moves within the magnetic field of a target, or indicate a diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java index d3274706631b..9e1c61aac868 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java @@ -23,6 +23,7 @@ import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.view.ContextThemeWrapper; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.animation.LinearInterpolator; @@ -33,7 +34,6 @@ import android.window.DisplayAreaOrganizer; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import androidx.appcompat.view.ContextThemeWrapper; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 954ca14b4960..e511bffad247 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -445,6 +445,9 @@ public class OneHandedController implements RemoteCallable mOneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, mContext.getContentResolver(), mShortcutEnabledObserver, newUserId); + mOneHandedSettingsUtil.registerSettingsKeyObserver( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + mContext.getContentResolver(), mShortcutEnabledObserver, newUserId); } private void unregisterSettingObservers() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index 7cf4fb7a811d..ff333c8c659d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -171,9 +171,22 @@ public final class OneHandedSettingsUtil { * @return true if user enabled one-handed shortcut in settings, false otherwise. */ public boolean getShortcutEnabled(ContentResolver resolver, int userId) { - final String targets = Settings.Secure.getStringForUser(resolver, + // Checks SOFTWARE_SHORTCUT_KEY + final String targetsSwKey = Settings.Secure.getStringForUser(resolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId); - return TextUtils.isEmpty(targets) ? false : targets.contains(ONE_HANDED_MODE_TARGET_NAME); + if (!TextUtils.isEmpty(targetsSwKey) && targetsSwKey.contains( + ONE_HANDED_MODE_TARGET_NAME)) { + return true; + } + + // Checks HARDWARE_SHORTCUT_KEY + final String targetsHwKey = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId); + if (!TextUtils.isEmpty(targetsHwKey) && targetsHwKey.contains( + ONE_HANDED_MODE_TARGET_NAME)) { + return true; + } + return false; } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index f58c6b173af9..81dd60d715e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -32,6 +32,7 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; import android.view.SurfaceControl; @@ -44,7 +45,6 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.appcompat.view.ContextThemeWrapper; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 4f3ec96968b2..63f1985aa86e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -303,13 +303,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb mOneHandedController = oneHandedController; mPipTransitionController = pipTransitionController; mTaskStackListener = taskStackListener; - mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(), - INPUT_CONSUMER_PIP, mainExecutor); //TODO: move this to ShellInit when PipController can be injected mMainExecutor.execute(this::init); } public void init() { + mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(), + INPUT_CONSUMER_PIP, mMainExecutor); mPipTransitionController.registerPipTransitionCallback(this); mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> { mPipBoundsState.setDisplayId(displayId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java index a5e96d14dde6..20021ebea834 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Binder; +import android.util.Log; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; @@ -45,7 +46,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; class SizeCompatUILayout { private static final String TAG = "SizeCompatUILayout"; - private final SyncTransactionQueue mSyncQueue; + final SyncTransactionQueue mSyncQueue; private final SizeCompatUIController.SizeCompatUICallback mCallback; private Context mContext; private Configuration mTaskConfig; @@ -306,6 +307,10 @@ class SizeCompatUILayout { private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) { mSyncQueue.runInSync(t -> { + if (!leash.isValid()) { + Log.w(TAG, "The leash has been released."); + return; + } t.setPosition(leash, positionX, positionY); // The size compat UI should be the topmost child of the Task in case there can be more // than one children. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java index f634c4586e39..82f69c3e2985 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java @@ -110,7 +110,8 @@ class SizeCompatUIWindowManager extends WindowlessWindowManager { } if (mLeash != null) { - new SurfaceControl.Transaction().remove(mLeash).apply(); + final SurfaceControl leash = mLeash; + mLayout.mSyncQueue.runInSync(t -> t.remove(leash)); mLeash = null; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index fc7c86d669cb..147f5e30f9d6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -545,6 +545,15 @@ public class StartingSurfaceDrawer { removeWindowSynced(taskId, null, null, false); } + void onImeDrawnOnTask(int taskId) { + final StartingWindowRecord record = mStartingWindowRecords.get(taskId); + if (record != null && record.mTaskSnapshotWindow != null + && record.mTaskSnapshotWindow.hasImeSurface()) { + record.mTaskSnapshotWindow.removeImmediately(); + } + mStartingWindowRecords.remove(taskId); + } + protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame, boolean playRevealAnimation) { final StartingWindowRecord record = mStartingWindowRecords.get(taskId); @@ -572,14 +581,15 @@ public class StartingSurfaceDrawer { Slog.e(TAG, "Found empty splash screen, remove!"); removeWindowInner(record.mDecorView, false); } + mStartingWindowRecords.remove(taskId); } if (record.mTaskSnapshotWindow != null) { if (DEBUG_TASK_SNAPSHOT) { Slog.v(TAG, "Removing task snapshot window for " + taskId); } - record.mTaskSnapshotWindow.remove(); + record.mTaskSnapshotWindow.scheduleRemove( + () -> mStartingWindowRecords.remove(taskId)); } - mStartingWindowRecords.remove(taskId); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index e84d498a9258..dee21b093dce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -176,6 +176,13 @@ public class StartingWindowController implements RemoteCallable mStartingSurfaceDrawer.onAppSplashScreenViewRemoved(taskId)); } + /** + * Called when the IME has drawn on the organized task. + */ + public void onImeDrawnOnTask(int taskId) { + mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.onImeDrawnOnTask(taskId)); + } + /** * Called when the content of a task is ready to show, starting window can be removed. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index 6052d3dee891..dfb1ae3ef2a0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -64,7 +64,6 @@ import android.graphics.RectF; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemClock; import android.os.Trace; import android.util.MergedConfiguration; import android.util.Slog; @@ -119,7 +118,12 @@ public class TaskSnapshotWindow { private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s"; private static final long DELAY_REMOVAL_TIME_GENERAL = 100; - private static final long DELAY_REMOVAL_TIME_IME_VISIBLE = 350; + /** + * The max delay time in milliseconds for removing the task snapshot window with IME visible. + * Ideally the delay time will be shorter when receiving + * {@link StartingSurfaceDrawer#onImeDrawnOnTask(int)}. + */ + private static final long MAX_DELAY_REMOVAL_TIME_IME_VISIBLE = 600; //tmp vars for unused relayout params private static final Point TMP_SURFACE_SIZE = new Point(); @@ -138,7 +142,6 @@ public class TaskSnapshotWindow { private final RectF mTmpDstFrame = new RectF(); private final CharSequence mTitle; private boolean mHasDrawn; - private long mShownTime; private boolean mSizeMismatch; private final Paint mBackgroundPaint = new Paint(); private final int mActivityType; @@ -148,6 +151,8 @@ public class TaskSnapshotWindow { private final SurfaceControl.Transaction mTransaction; private final Matrix mSnapshotMatrix = new Matrix(); private final float[] mTmpFloat9 = new float[9]; + private Runnable mScheduledRunnable; + private final boolean mHasImeSurface; static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken, TaskSnapshot snapshot, ShellExecutor splashScreenExecutor, @@ -216,7 +221,7 @@ public class TaskSnapshotWindow { taskDescription.setBackgroundColor(WHITE); } - final long delayRemovalTime = snapshot.hasImeSurface() ? DELAY_REMOVAL_TIME_IME_VISIBLE + final long delayRemovalTime = snapshot.hasImeSurface() ? MAX_DELAY_REMOVAL_TIME_IME_VISIBLE : DELAY_REMOVAL_TIME_GENERAL; final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow( @@ -281,12 +286,17 @@ public class TaskSnapshotWindow { mDelayRemovalTime = delayRemovalTime; mTransaction = new SurfaceControl.Transaction(); mClearWindowHandler = clearWindowHandler; + mHasImeSurface = snapshot.hasImeSurface(); } int getBackgroundColor() { return mBackgroundPaint.getColor(); } + boolean hasImeSurface() { + return mHasImeSurface; + } + /** * Ask system bar background painter to draw status bar background. * @hide @@ -304,21 +314,32 @@ public class TaskSnapshotWindow { mSystemBarBackgroundPainter.drawNavigationBarBackground(c); } - void remove() { - final long now = SystemClock.uptimeMillis(); - if ((now - mShownTime < mDelayRemovalTime) - // Show the latest content as soon as possible for unlocking to home. - && mActivityType != ACTIVITY_TYPE_HOME) { - final long delayTime = mShownTime + mDelayRemovalTime - now; - mSplashScreenExecutor.executeDelayed(() -> remove(), delayTime); - if (DEBUG) { - Slog.d(TAG, "Defer removing snapshot surface in " + delayTime); - } + void scheduleRemove(Runnable onRemove) { + // Show the latest content as soon as possible for unlocking to home. + if (mActivityType == ACTIVITY_TYPE_HOME) { + removeImmediately(); + onRemove.run(); return; } + if (mScheduledRunnable != null) { + mSplashScreenExecutor.removeCallbacks(mScheduledRunnable); + mScheduledRunnable = null; + } + mScheduledRunnable = () -> { + TaskSnapshotWindow.this.removeImmediately(); + onRemove.run(); + }; + mSplashScreenExecutor.executeDelayed(mScheduledRunnable, mDelayRemovalTime); + if (DEBUG) { + Slog.d(TAG, "Defer removing snapshot surface in " + mDelayRemovalTime); + } + } + + void removeImmediately() { + mSplashScreenExecutor.removeCallbacks(mScheduledRunnable); try { if (DEBUG) { - Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn); + Slog.d(TAG, "Removing taskSnapshot surface, mHasDrawn: " + mHasDrawn); } mSession.remove(mWindow); } catch (RemoteException e) { @@ -356,7 +377,6 @@ public class TaskSnapshotWindow { } else { drawSizeMatchSnapshot(); } - mShownTime = SystemClock.uptimeMillis(); mHasDrawn = true; reportDrawn(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index d536adb9f8ae..eef0d9bb268f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -15,38 +15,53 @@ */ package com.android.wm.shell.startingsurface; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.graphics.ColorSpace; +import android.graphics.Point; import android.graphics.Rect; +import android.hardware.HardwareBuffer; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.UserHandle; import android.testing.TestableContext; +import android.view.IWindowSession; +import android.view.InsetsState; +import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.view.WindowMetrics; import android.window.StartingWindowInfo; +import android.window.TaskSnapshot; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -61,6 +76,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; import java.util.function.IntSupplier; @@ -78,6 +94,7 @@ public class StartingSurfaceDrawerTests { private TransactionPool mTransactionPool; private final Handler mTestHandler = new Handler(Looper.getMainLooper()); + private ShellExecutor mTestExecutor; private final TestableContext mTestContext = new TestContext( InstrumentationRegistry.getInstrumentation().getTargetContext()); TestStartingSurfaceDrawer mStartingSurfaceDrawer; @@ -138,9 +155,9 @@ public class StartingSurfaceDrawerTests { doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics(); doNothing().when(mMockWindowManager).addView(any(), any()); - - mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(mTestContext, - new HandlerExecutor(mTestHandler), mTransactionPool)); + mTestExecutor = new HandlerExecutor(mTestHandler); + mStartingSurfaceDrawer = spy( + new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mTransactionPool)); } @Test @@ -205,6 +222,48 @@ public class StartingSurfaceDrawerTests { assertEquals(0, windowColor3.mReuseCount); } + @Test + public void testRemoveTaskSnapshotWithImeSurfaceWhenOnImeDrawn() throws Exception { + final int taskId = 1; + final StartingWindowInfo windowInfo = + createWindowInfo(taskId, android.R.style.Theme); + TaskSnapshot snapshot = createTaskSnapshot(100, 100, new Point(100, 100), + new Rect(0, 0, 0, 50), true /* hasImeSurface */); + final IWindowSession session = WindowManagerGlobal.getWindowSession(); + spyOn(session); + doReturn(WindowManagerGlobal.ADD_OKAY).when(session).addToDisplay( + any() /* window */, any() /* attrs */, + anyInt() /* viewVisibility */, anyInt() /* displayId */, + any() /* requestedVisibility */, any() /* outInputChannel */, + any() /* outInsetsState */, any() /* outActiveControls */); + TaskSnapshotWindow mockSnapshotWindow = TaskSnapshotWindow.create(windowInfo, + mBinder, + snapshot, mTestExecutor, () -> { + }); + spyOn(mockSnapshotWindow); + try (AutoCloseable mockTaskSnapshotSession = new AutoCloseable() { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(TaskSnapshotWindow.class) + .startMocking(); + @Override + public void close() { + mockSession.finishMocking(); + } + }) { + when(TaskSnapshotWindow.create(eq(windowInfo), eq(mBinder), eq(snapshot), any(), + any())).thenReturn(mockSnapshotWindow); + // Simulate a task snapshot window created with IME snapshot shown. + mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, mBinder, snapshot); + waitHandlerIdle(mTestHandler); + + // Verify the task snapshot with IME snapshot will be removed when received the real IME + // drawn callback. + mStartingSurfaceDrawer.onImeDrawnOnTask(1); + verify(mockSnapshotWindow).removeImmediately(); + } + } + private StartingWindowInfo createWindowInfo(int taskId, int themeResId) { StartingWindowInfo windowInfo = new StartingWindowInfo(); final ActivityInfo info = new ActivityInfo(); @@ -216,10 +275,27 @@ public class StartingSurfaceDrawerTests { taskInfo.taskId = taskId; windowInfo.targetActivityInfo = info; windowInfo.taskInfo = taskInfo; + windowInfo.topOpaqueWindowInsetsState = new InsetsState(); + windowInfo.mainWindowLayoutParams = new WindowManager.LayoutParams(); + windowInfo.topOpaqueWindowLayoutParams = new WindowManager.LayoutParams(); return windowInfo; } private static void waitHandlerIdle(Handler handler) { handler.runWithScissors(() -> { }, 0 /* timeout */); } + + private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize, + Rect contentInsets, boolean hasImeSurface) { + final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, + 1, HardwareBuffer.USAGE_CPU_READ_RARELY); + return new TaskSnapshot( + System.currentTimeMillis(), + new ComponentName("", ""), buffer, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + Surface.ROTATION_0, taskSize, contentInsets, false, + true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, + 0 /* systemUiVisibility */, false /* isTranslucent */, + hasImeSurface /* hasImeSurface */); + } } diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS index 17f5164cf417..38b642501fcd 100644 --- a/libs/androidfw/OWNERS +++ b/libs/androidfw/OWNERS @@ -1,5 +1,4 @@ set noparent -toddke@google.com zyy@google.com patb@google.com diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index c804418e8380..513ad9aab9ff 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -50,6 +50,7 @@ bool Properties::showDirtyRegions = false; bool Properties::skipEmptyFrames = true; bool Properties::useBufferAge = true; bool Properties::enablePartialUpdates = true; +bool Properties::enableRenderEffectCache = false; DebugLevel Properties::debugLevel = kDebugDisabled; OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default; @@ -84,7 +85,7 @@ float Properties::defaultSdrWhitePoint = 200.f; bool Properties::useHintManager = true; int Properties::targetCpuTimePercentage = 70; -bool Properties::enableWebViewOverlays = false; +bool Properties::enableWebViewOverlays = true; StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; @@ -141,7 +142,7 @@ bool Properties::load() { targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70); if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70; - enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false); + enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, true); // call isDrawingEnabled to force loading of the property isDrawingEnabled(); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7f9782bf8d20..2f8c67903a8b 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -232,6 +232,7 @@ public: static bool skipEmptyFrames; static bool useBufferAge; static bool enablePartialUpdates; + static bool enableRenderEffectCache; // TODO: Move somewhere else? static constexpr float textGamma = 1.45f; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 0c422df65881..b348a6ecaae4 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -341,6 +341,7 @@ std::optional RenderNode::updateSnapshotIfRequired( sk_sp snapshot = layerSurface->makeImageSnapshot(); const auto subset = SkIRect::MakeWH(properties().getWidth(), properties().getHeight()); + uint32_t layerSurfaceGenerationId = layerSurface->generationID(); // If we don't have an ImageFilter just return the snapshot if (imageFilter == nullptr) { mSnapshotResult.snapshot = snapshot; @@ -348,9 +349,10 @@ std::optional RenderNode::updateSnapshotIfRequired( mSnapshotResult.outOffset = SkIPoint::Make(0.0f, 0.0f); mImageFilterClipBounds = clipBounds; mTargetImageFilter = nullptr; - } else if (mSnapshotResult.snapshot == nullptr || - imageFilter != mTargetImageFilter.get() || - mImageFilterClipBounds != clipBounds) { + mTargetImageFilterLayerSurfaceGenerationId = 0; + } else if (mSnapshotResult.snapshot == nullptr || imageFilter != mTargetImageFilter.get() || + mImageFilterClipBounds != clipBounds || + mTargetImageFilterLayerSurfaceGenerationId != layerSurfaceGenerationId) { // Otherwise create a new snapshot with the given filter and snapshot mSnapshotResult.snapshot = snapshot->makeWithFilter(context, @@ -361,6 +363,7 @@ std::optional RenderNode::updateSnapshotIfRequired( &mSnapshotResult.outOffset); mTargetImageFilter = sk_ref_sp(imageFilter); mImageFilterClipBounds = clipBounds; + mTargetImageFilterLayerSurfaceGenerationId = layerSurfaceGenerationId; } return mSnapshotResult; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 45a4f6c9c70d..da0476259b97 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -396,6 +396,7 @@ private: * SkImageFilter used to create the mSnapshotResult */ sk_sp mTargetImageFilter; + uint32_t mTargetImageFilterLayerSurfaceGenerationId = 0; /** * Clip bounds used to create the mSnapshotResult diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp index df4101109a18..5aad821ad59f 100644 --- a/libs/hwui/WebViewFunctorManager.cpp +++ b/libs/hwui/WebViewFunctorManager.cpp @@ -100,6 +100,9 @@ WebViewFunctor::~WebViewFunctor() { destroyContext(); ATRACE_NAME("WebViewFunctor::onDestroy"); + if (mSurfaceControl) { + removeOverlays(); + } mCallbacks.onDestroyed(mFunctor, mData); } diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 7556af918170..48145d2331ee 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -231,14 +231,33 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer); SkPaint paint; layerNeedsPaint(layerProperties, alphaMultiplier, &paint); - const auto snapshotResult = renderNode->updateSnapshotIfRequired( - canvas->recordingContext(), - layerProperties.getImageFilter(), - clipBounds.roundOut() - ); - sk_sp snapshotImage = snapshotResult->snapshot; - srcBounds = snapshotResult->outSubset; - offset = snapshotResult->outOffset; + sk_sp snapshotImage; + auto* imageFilter = layerProperties.getImageFilter(); + auto recordingContext = canvas->recordingContext(); + // On some GL vendor implementations, caching the result of + // getLayerSurface->makeImageSnapshot() causes a call to + // Fence::waitForever without a corresponding signal. This would + // lead to ANRs throughout the system. + // Instead only cache the SkImage created with the SkImageFilter + // for supported devices. Otherwise just create a new SkImage with + // the corresponding SkImageFilter each time. + // See b/193145089 and b/197263715 + if (!Properties::enableRenderEffectCache) { + snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot(); + if (imageFilter) { + auto subset = SkIRect::MakeWH(srcBounds.width(), srcBounds.height()); + snapshotImage = snapshotImage->makeWithFilter(recordingContext, imageFilter, + subset, clipBounds.roundOut(), + &srcBounds, &offset); + } + } else { + const auto snapshotResult = renderNode->updateSnapshotIfRequired( + recordingContext, layerProperties.getImageFilter(), clipBounds.roundOut()); + snapshotImage = snapshotResult->snapshot; + srcBounds = snapshotResult->outSubset; + offset = snapshotResult->outOffset; + } + const auto dstBounds = SkIRect::MakeXYWH(offset.x(), offset.y(), srcBounds.width(), diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index a11678189bad..383c79b27918 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -146,6 +146,9 @@ void EglManager::initialize() { LOG_ALWAYS_FATAL("Unsupported wide color space."); } mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension; + + auto* vendor = reinterpret_cast(glGetString(GL_VENDOR)); + Properties::enableRenderEffectCache = (strcmp(vendor, "Qualcomm") != 0); } EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) { diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java index dc1e99fd6a4f..2b978f759a13 100644 --- a/location/java/android/location/GpsNavigationMessage.java +++ b/location/java/android/location/GpsNavigationMessage.java @@ -262,12 +262,8 @@ public class GpsNavigationMessage implements Parcelable { parcel.readByteArray(data); navigationMessage.setData(data); - if (parcel.dataAvail() >= Integer.SIZE) { - int status = parcel.readInt(); - navigationMessage.setStatus((short) status); - } else { - navigationMessage.setStatus(STATUS_UNKNOWN); - } + int status = parcel.readInt(); + navigationMessage.setStatus((short) status); return navigationMessage; } diff --git a/media/java/android/media/IMediaRouterClient.aidl b/media/java/android/media/IMediaRouterClient.aidl index 6b754e157cfb..9b4912373122 100644 --- a/media/java/android/media/IMediaRouterClient.aidl +++ b/media/java/android/media/IMediaRouterClient.aidl @@ -23,5 +23,4 @@ oneway interface IMediaRouterClient { void onStateChanged(); void onRestoreRoute(); void onGroupRouteSelected(String routeId); - void onGlobalA2dpChanged(boolean a2dpOn); } diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 345d9b27c8a8..2986f7c75f4d 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -654,9 +654,12 @@ public class MediaRouter { final class Client extends IMediaRouterClient.Stub { @Override public void onStateChanged() { - mHandler.post(() -> { - if (Client.this == mClient) { - updateClientState(); + mHandler.post(new Runnable() { + @Override + public void run() { + if (Client.this == mClient) { + updateClientState(); + } } }); } @@ -690,26 +693,6 @@ public class MediaRouter { } }); } - - // Called when the selection of a connected device (phone speaker or BT devices) - // is changed. - @Override - public void onGlobalA2dpChanged(boolean a2dpOn) { - mHandler.post(() -> { - if (mSelectedRoute == null || mBluetoothA2dpRoute == null) { - return; - } - if (mSelectedRoute.isDefault() && a2dpOn) { - setSelectedRoute(mBluetoothA2dpRoute, /*explicit=*/ false); - dispatchRouteUnselected(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo); - dispatchRouteSelected(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute); - } else if (mSelectedRoute.isBluetooth() && !a2dpOn) { - setSelectedRoute(mDefaultAudioVideo, /*explicit=*/ false); - dispatchRouteUnselected(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute); - dispatchRouteSelected(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo); - } - }); - } } } @@ -1367,9 +1350,6 @@ public class MediaRouter { } static void dispatchRouteSelected(int type, RouteInfo info) { - if (DEBUG) { - Log.d(TAG, "Dispatching route selected: " + info); - } for (CallbackInfo cbi : sStatic.mCallbacks) { if (cbi.filterRouteEvent(info)) { cbi.cb.onRouteSelected(cbi.router, type, info); @@ -1378,9 +1358,6 @@ public class MediaRouter { } static void dispatchRouteUnselected(int type, RouteInfo info) { - if (DEBUG) { - Log.d(TAG, "Dispatching route unselected: " + info); - } for (CallbackInfo cbi : sStatic.mCallbacks) { if (cbi.filterRouteEvent(info)) { cbi.cb.onRouteUnselected(cbi.router, type, info); diff --git a/native/android/OWNERS b/native/android/OWNERS index 02dfd393a0b7..8b35f8d38691 100644 --- a/native/android/OWNERS +++ b/native/android/OWNERS @@ -1,7 +1,7 @@ jreck@google.com per-file libandroid_net.map.txt, net.c = set noparent -per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com +per-file libandroid_net.map.txt, net.c = jchalard@google.com, junyulai@google.com per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS diff --git a/packages/CtsShim/OWNERS b/packages/CtsShim/OWNERS index 94197715150d..eb631bc7cbcf 100644 --- a/packages/CtsShim/OWNERS +++ b/packages/CtsShim/OWNERS @@ -1,3 +1,2 @@ ioffe@google.com -toddke@google.com patb@google.com \ No newline at end of file diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index 48cdf1647d86..197b7b2b0eaf 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -31,7 +31,7 @@ android:directBootAware="true"> + android:exported="false"> @@ -76,7 +76,7 @@ + android:exported="false"> @@ -106,14 +106,14 @@ + android:exported="false"> + android:exported="false"> diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING index 5d7b9bb36f75..cef9014ec229 100644 --- a/packages/PackageInstaller/TEST_MAPPING +++ b/packages/PackageInstaller/TEST_MAPPING @@ -19,6 +19,9 @@ }, { "name": "CtsPackageUninstallTestCases" + }, + { + "name": "PackageInstallerTests" } ] -} \ No newline at end of file +} diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java index 5f107d662b75..34e7e3d1cd6b 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java @@ -84,8 +84,7 @@ public class MDNSFilterPlugin implements PrintServicePlugin { */ public MDNSFilterPlugin(@NonNull Context context, @NonNull String name, @NonNull CharSequence packageName, @NonNull List mDNSNames) { - mName = context.getResources().getIdentifier(name, null, - "com.android.printservice.recommendation"); + mName = context.getResources().getIdentifier(name, null, context.getPackageName()); mPackageName = packageName; mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPES, new VendorNameFilter(new HashSet<>(mDNSNames))); diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml index e74ac44ec8a4..fede44feb090 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml @@ -33,18 +33,18 @@ @@ -58,4 +58,4 @@ parent="android:Widget.DeviceDefault.Button.Borderless.Colored"> ?android:attr/colorAccent - \ No newline at end of file + diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml index df47c642e402..4c6ed58f4a58 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml @@ -17,14 +17,13 @@ diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml index 92514ad58b77..1c4420717188 100644 --- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml +++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml @@ -87,9 +87,9 @@ diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp index 2f911c4e6546..238e65ec9a3c 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp @@ -19,6 +19,7 @@ android_library { "com.google.android.material_material", "SettingsLibSettingsTransition", "SettingsLibUtils", + "SettingsLibSettingsTheme", ], sdk_version: "system_current", min_sdk_version: "29", diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml index 59506564400b..907863e19972 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml @@ -16,7 +16,6 @@ --> true ?attr/colorPrimary - @*android:color/primary_dark_device_default_settings - @*android:color/accent_device_default_dark + @color/settingslib_primary_dark_device_default_settings + @color/settingslib_accent_device_default_dark \ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml similarity index 100% rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml similarity index 76% rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml index 63d397c69353..d0b6c4d54bb1 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml @@ -16,11 +16,13 @@ --> \ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml similarity index 82% rename from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml rename to packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml index 2e7a6a9181fe..9ecc297c6d36 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml @@ -18,7 +18,7 @@ \ No newline at end of file diff --git a/packages/SettingsLib/FooterPreference/res/values/styles.xml b/packages/SettingsLib/FooterPreference/res/values/styles.xml index 08dd35991f69..5a3bada3e594 100644 --- a/packages/SettingsLib/FooterPreference/res/values/styles.xml +++ b/packages/SettingsLib/FooterPreference/res/values/styles.xml @@ -17,9 +17,8 @@ \ No newline at end of file diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/LayoutPreference/res/values/styles.xml index 4a99e845a5fc..2ffe6d91651b 100644 --- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml +++ b/packages/SettingsLib/LayoutPreference/res/values/styles.xml @@ -24,14 +24,13 @@ + diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml index 16b8af6a2dab..6362882e2332 100644 --- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml +++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml @@ -1,6 +1,6 @@ - 16dp - - - 24dp - - - 16dp - - - 52dp - - - 72dp - - @*android:dimen/config_restrictedIconSize + @android:dimen/config_restrictedIconSize 16dp - - 28dp - 16dp diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml index 3924e301a2d3..870812ae6caf 100644 --- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml +++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml @@ -1,6 +1,6 @@ + + + \ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml index 8c7c7ed5b120..c20690342c19 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml @@ -36,4 +36,11 @@ #f28b82 @android:color/system_neutral1_700 + + @android:color/system_neutral1_700 + + + @android:color/system_accent1_300 + + @android:color/system_neutral1_50 \ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml index 77f1bcd17371..04010985fe74 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml @@ -37,9 +37,32 @@ @android:color/system_accent1_600 - @*android:color/surface_light + @color/settingslib_surface_light #d93025 @android:color/system_neutral2_100 + + @android:color/system_neutral1_100 + + @android:color/system_accent1_100 + + @android:color/system_accent1_600 + + @android:color/system_neutral1_900 + + @android:color/system_neutral1_50 + + @android:color/system_accent1_100 + + + @android:color/system_accent1_600 + + @android:color/system_accent2_100 + + @android:color/system_neutral1_900 + + @android:color/system_neutral1_50 + + @android:color/system_neutral1_900 diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml index ddcc83eee4bf..1c33f1a57ea5 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml @@ -19,4 +19,5 @@ 20dp 52dp 48dp + 28dp diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml new file mode 100644 index 000000000000..6d072a936b15 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml @@ -0,0 +1,37 @@ + + + + + + + @*android:string/config_headlineFontFamily + + + + + @*android:string/config_headlineFontFamilyMedium + + + + + @*android:string/config_bodyFontFamily + + + + + @*android:string/config_bodyFontFamilyMedium + + diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml index 46f1e030af23..58006369988e 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml @@ -16,12 +16,16 @@ --> \ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml index 25f9514c29b7..18af1f9c15d0 100644 --- a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml @@ -20,4 +20,5 @@ ?android:attr/listPreferredItemPaddingStart 56dp 72dp + 8dp diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml index 6f2517746ddc..2d881d1a8a7b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml @@ -35,7 +35,7 @@ adjustResize true diff --git a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml index 65869b5580b5..b6ca41fb6b6d 100644 --- a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml +++ b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml @@ -16,8 +16,7 @@ --> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 72fa25fc7a3a..bf0dc7bce5f9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -157,7 +157,6 @@ public class WifiStatusTracker { private Network mDefaultNetwork = null; private NetworkCapabilities mDefaultNetworkCapabilities = null; private final Runnable mCallback; - private final boolean mSupportMergedUi; private WifiInfo mWifiInfo; public boolean enabled; @@ -181,7 +180,6 @@ public class WifiStatusTracker { mNetworkScoreManager = networkScoreManager; mConnectivityManager = connectivityManager; mCallback = callback; - mSupportMergedUi = false; } public void setListening(boolean listening) { @@ -223,10 +221,8 @@ public class WifiStatusTracker { } else { ssid = getValidSsid(mWifiInfo); } - if (mSupportMergedUi) { - isCarrierMerged = mWifiInfo.isCarrierMerged(); - subId = mWifiInfo.getSubscriptionId(); - } + isCarrierMerged = mWifiInfo.isCarrierMerged(); + subId = mWifiInfo.getSubscriptionId(); updateRssi(mWifiInfo.getRssi()); maybeRequestNetworkScore(); } @@ -255,10 +251,8 @@ public class WifiStatusTracker { } else { ssid = getValidSsid(mWifiInfo); } - if (mSupportMergedUi) { - isCarrierMerged = mWifiInfo.isCarrierMerged(); - subId = mWifiInfo.getSubscriptionId(); - } + isCarrierMerged = mWifiInfo.isCarrierMerged(); + subId = mWifiInfo.getSubscriptionId(); updateRssi(mWifiInfo.getRssi()); maybeRequestNetworkScore(); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index 61006156d8aa..56454e975370 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -20,10 +20,13 @@ import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_ import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason; import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiInfo; +import android.os.Bundle; import android.os.SystemClock; import androidx.annotation.VisibleForTesting; @@ -36,6 +39,23 @@ public class WifiUtils { private static final int INVALID_RSSI = -127; + /** + * The intent action shows network details settings to allow configuration of Wi-Fi. + *

+ * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

+ * Input: The calling package should put the chosen + * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into + * the {@link #KEY_CHOSEN_WIFIENTRY_KEY}. + *

+ * Output: Nothing. + */ + public static final String ACTION_WIFI_DETAILS_SETTINGS = + "android.settings.WIFI_DETAILS_SETTINGS"; + public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; + public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; + static final int[] WIFI_PIE = { com.android.internal.R.drawable.ic_wifi_signal_0, com.android.internal.R.drawable.ic_wifi_signal_1, @@ -275,7 +295,42 @@ public class WifiUtils { return noInternet ? NO_INTERNET_WIFI_PIE[level] : WIFI_PIE[level]; } + /** + * Wrapper the {@link #getInternetIconResource} for testing compatibility. + */ + public static class InternetIconInjector { + + protected final Context mContext; + + public InternetIconInjector(Context context) { + mContext = context; + } + + /** + * Returns the Internet icon for a given RSSI level. + * + * @param noInternet True if a connected Wi-Fi network cannot access the Internet + * @param level The number of bars to show (0-4) + */ + public Drawable getIcon(boolean noInternet, int level) { + return mContext.getDrawable(WifiUtils.getInternetIconResource(level, noInternet)); + } + } + public static boolean isMeteredOverridden(WifiConfiguration config) { return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE; } + + /** + * Returns the Intent for Wi-Fi network details settings. + * + * @param key The Wi-Fi entry key + */ + public static Intent getWifiDetailsSettingsIntent(String key) { + final Intent intent = new Intent(ACTION_WIFI_DETAILS_SETTINGS); + final Bundle bundle = new Bundle(); + bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key); + intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle); + return intent; + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java index 89960cba2bf5..7c2b904fc576 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java @@ -20,9 +20,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.Intent; import android.net.NetworkKey; import android.net.RssiCurve; import android.net.ScoredNetwork; @@ -36,6 +39,8 @@ import android.os.SystemClock; import android.text.format.DateUtils; import android.util.ArraySet; +import androidx.test.core.app.ApplicationProvider; + import com.android.settingslib.R; import org.junit.Before; @@ -44,7 +49,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.Set; @@ -69,7 +73,7 @@ public class WifiUtilsTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(ApplicationProvider.getApplicationContext()); } @Test @@ -148,6 +152,32 @@ public class WifiUtilsTest { assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue(); } + @Test + public void getWifiDetailsSettingsIntent_returnsCorrectValues() { + final String key = "test_key"; + + final Intent intent = WifiUtils.getWifiDetailsSettingsIntent(key); + + assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DETAILS_SETTINGS); + final Bundle bundle = intent.getBundleExtra(WifiUtils.EXTRA_SHOW_FRAGMENT_ARGUMENTS); + assertThat(bundle.getString(WifiUtils.KEY_CHOSEN_WIFIENTRY_KEY)).isEqualTo(key); + } + + @Test + public void testInternetIconInjector_getIcon_returnsCorrectValues() { + WifiUtils.InternetIconInjector iconInjector = new WifiUtils.InternetIconInjector(mContext); + + for (int level = 0; level <= 4; level++) { + iconInjector.getIcon(false /* noInternet */, level); + verify(mContext).getDrawable( + WifiUtils.getInternetIconResource(level, false /* noInternet */)); + + iconInjector.getIcon(true /* noInternet */, level); + verify(mContext).getDrawable( + WifiUtils.getInternetIconResource(level, true /* noInternet */)); + } + } + private static ArrayList buildScanResultCache() { ArrayList scanResults = new ArrayList<>(); for (int i = 0; i < 5; i++) { diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java index eb8196176034..a46d28b273e5 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java @@ -76,5 +76,6 @@ public class GlobalSettings { Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED, Settings.Global.DEVICE_CONFIG_SYNC_DISABLED, Settings.Global.POWER_BUTTON_LONG_PRESS, + Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 60226084c70d..96f127b6a611 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -101,6 +101,7 @@ public class SecureSettings { Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, Settings.Secure.QS_TILES, + Settings.Secure.QS_AUTO_ADDED_TILES, Settings.Secure.CONTROLS_ENABLED, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, Settings.Secure.DOZE_ENABLED, @@ -118,7 +119,6 @@ public class SecureSettings { Settings.Secure.VR_DISPLAY_MODE, Settings.Secure.NOTIFICATION_BADGING, Settings.Secure.NOTIFICATION_DISMISS_RTL, - Settings.Secure.QS_AUTO_ADDED_TILES, Settings.Secure.SCREENSAVER_ENABLED, Settings.Secure.SCREENSAVER_COMPONENTS, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index 5220a04d73e6..84c5febcb5a2 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -20,6 +20,7 @@ import static android.media.AudioFormat.SURROUND_SOUND_ENCODING; import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.PERCENTAGE_INTEGER_VALIDATOR; import static android.view.Display.HdrCapabilities.HDR_TYPES; @@ -140,6 +141,7 @@ public class GlobalSettingsValidators { /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT)); VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, NONE_NEGATIVE_LONG_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index c57786888e8d..6cfcb51239a3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -72,8 +72,9 @@ public class SettingsHelper { * {@hide} */ private static final ArraySet sBroadcastOnRestore; + private static final ArraySet sBroadcastOnRestoreSystemUI; static { - sBroadcastOnRestore = new ArraySet(4); + sBroadcastOnRestore = new ArraySet(9); sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); @@ -83,6 +84,9 @@ public class SettingsHelper { sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME); sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED); sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + sBroadcastOnRestoreSystemUI = new ArraySet(2); + sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES); + sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_AUTO_ADDED_TILES); } private interface SettingsLookup { @@ -133,6 +137,7 @@ public class SettingsHelper { // Will we need a post-restore broadcast for this element? String oldValue = null; boolean sendBroadcast = false; + boolean sendBroadcastSystemUI = false; final SettingsLookup table; if (destination.equals(Settings.Secure.CONTENT_URI)) { @@ -143,10 +148,12 @@ public class SettingsHelper { table = sGlobalLookup; } - if (sBroadcastOnRestore.contains(name)) { + sendBroadcast = sBroadcastOnRestore.contains(name); + sendBroadcastSystemUI = sBroadcastOnRestoreSystemUI.contains(name); + + if (sendBroadcast || sendBroadcastSystemUI) { // TODO: http://b/22388012 oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM); - sendBroadcast = true; } try { @@ -193,18 +200,28 @@ public class SettingsHelper { } catch (Exception e) { // If we fail to apply the setting, by definition nothing happened sendBroadcast = false; + sendBroadcastSystemUI = false; } finally { // If this was an element of interest, send the "we just restored it" // broadcast with the historical value now that the new value has // been committed and observers kicked off. - if (sendBroadcast) { + if (sendBroadcast || sendBroadcastSystemUI) { Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED) - .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) .putExtra(Intent.EXTRA_SETTING_NAME, name) .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value) .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue) .putExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, restoredFromSdkInt); - context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); + + if (sendBroadcast) { + intent.setPackage("android"); + context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); + } + if (sendBroadcastSystemUI) { + intent.setPackage( + context.getString(com.android.internal.R.string.config_systemUi)); + context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); + } } } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 073b4d00653d..4ac19386db0a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -762,9 +762,6 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES); - dumpSetting(s, p, - Settings.Global.ANGLE_ALLOWLIST, - GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST); dumpSetting(s, p, Settings.Global.ANGLE_EGL_FEATURES, GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES); @@ -1195,6 +1192,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.POWER_MANAGER_CONSTANTS, GlobalSettingsProto.POWER_MANAGER_CONSTANTS); + dumpSetting(s, p, + Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, + GlobalSettingsProto.POWER_BUTTON_LONG_PRESS_DURATION_MS); final long prepaidSetupToken = p.start(GlobalSettingsProto.PREPAID_SETUP); dumpSetting(s, p, @@ -1475,6 +1475,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.USE_OPEN_WIFI_PACKAGE, GlobalSettingsProto.USE_OPEN_WIFI_PACKAGE); + dumpSetting(s, p, + Settings.Global.UWB_ENABLED, + GlobalSettingsProto.UWB_ENABLED); dumpSetting(s, p, Settings.Global.VT_IMS_ENABLED, GlobalSettingsProto.VT_IMS_ENABLED); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 3297937e3e75..7db73c697ea7 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -509,7 +509,6 @@ public class SettingsBackupTest { Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE, Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, - Settings.Global.ANGLE_ALLOWLIST, Settings.Global.ANGLE_EGL_FEATURES, Settings.Global.UPDATABLE_DRIVER_ALL_APPS, Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS, @@ -519,6 +518,7 @@ public class SettingsBackupTest { Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST, Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST, Settings.Global.UPDATABLE_DRIVER_SPHAL_LIBRARIES, + Settings.Global.UWB_ENABLED, Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, Settings.Global.GPU_DEBUG_LAYER_APP, Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS index 177f86b08864..80bb307749ed 100644 --- a/packages/Shell/OWNERS +++ b/packages/Shell/OWNERS @@ -6,7 +6,6 @@ nandana@google.com svetoslavganov@google.com hackbod@google.com yamasani@google.com -toddke@google.com patb@google.com cbrubaker@google.com omakoto@google.com diff --git a/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml b/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml new file mode 100644 index 000000000000..495fbb893eac --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/packages/SystemUI/res-keyguard/values/donottranslate.xml b/packages/SystemUI/res-keyguard/values/donottranslate.xml index a4d0ff7269a2..1934457b4bc6 100644 --- a/packages/SystemUI/res-keyguard/values/donottranslate.xml +++ b/packages/SystemUI/res-keyguard/values/donottranslate.xml @@ -21,6 +21,9 @@ EEEMMMd + + MMMd + hm diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 72b027af1bf6..098b7e8dedbe 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -142,4 +142,8 @@ @color/keyguard_shadow_color ?attr/shadowRadius + + diff --git a/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml new file mode 100644 index 000000000000..13133cb451e4 --- /dev/null +++ b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_state_off.xml b/packages/SystemUI/res/color/settingslib_state_off.xml new file mode 100644 index 000000000000..e8218259087d --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_state_off.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_state_on.xml b/packages/SystemUI/res/color/settingslib_state_on.xml new file mode 100644 index 000000000000..6d2133c5bacf --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_state_on.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_track_off.xml b/packages/SystemUI/res/color/settingslib_track_off.xml new file mode 100644 index 000000000000..21d1dccbf900 --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_track_off.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_track_on.xml b/packages/SystemUI/res/color/settingslib_track_on.xml new file mode 100644 index 000000000000..ba7848a5d23e --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_track_on.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml index 33263a9131a0..0ae5dc745478 100644 --- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml +++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml @@ -1,201 +1,142 @@ - + + + xmlns:aapt="http://schemas.android.com/aapt"> - + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + - + - + - + - + - + - + + + + + + + + + + + - + - + - + - + - + + + + + + + + + + + @@ -204,182 +145,58 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -388,26 +205,38 @@ - + - + - + - + + + + + + + + + + + + + + + + + @@ -416,14 +245,10 @@ - + - \ No newline at end of file + diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml index b899828cd85c..fc2c7d00f3a7 100644 --- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml +++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml @@ -1,179 +1,170 @@ - + + + xmlns:aapt="http://schemas.android.com/aapt"> - + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -182,193 +173,37 @@ - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -377,15 +212,24 @@ - + - + + + + + + + + + + + + @@ -394,14 +238,10 @@ - + - \ No newline at end of file + diff --git a/packages/SystemUI/res/drawable/ic_arrow_forward.xml b/packages/SystemUI/res/drawable/ic_arrow_forward.xml new file mode 100644 index 000000000000..438e4c70dc71 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_arrow_forward.xml @@ -0,0 +1,26 @@ + + + + diff --git a/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml new file mode 100644 index 000000000000..2c34060ccd61 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/packages/SystemUI/res/drawable/ic_media_home_devices.xml b/packages/SystemUI/res/drawable/ic_media_home_devices.xml new file mode 100644 index 000000000000..886c64d9bf02 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_media_home_devices.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml new file mode 100644 index 000000000000..ac4c43bd35b9 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml new file mode 100644 index 000000000000..f38a36804bc8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml @@ -0,0 +1,34 @@ + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_background.xml b/packages/SystemUI/res/drawable/internet_dialog_background.xml new file mode 100644 index 000000000000..3ceb0f6ac06a --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_background.xml @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml new file mode 100644 index 000000000000..50267fda0b25 --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml new file mode 100644 index 000000000000..14672ef3dcfe --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable/logout_button_background.xml b/packages/SystemUI/res/drawable/logout_button_background.xml index eafd663f19d9..34434be7aefb 100644 --- a/packages/SystemUI/res/drawable/logout_button_background.xml +++ b/packages/SystemUI/res/drawable/logout_button_background.xml @@ -17,7 +17,8 @@ --> - + diff --git a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml index 6725a26c102c..e6266754c0af 100644 --- a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml +++ b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml @@ -14,19 +14,20 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - - - - - - - - \ No newline at end of file + android:color="?android:attr/colorControlHighlight"> + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml new file mode 100644 index 000000000000..95209f8eb8ab --- /dev/null +++ b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml new file mode 100644 index 000000000000..088e82bb4260 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml new file mode 100644 index 000000000000..250188b892f4 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml new file mode 100644 index 000000000000..b41762f7908e --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_off.xml b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml new file mode 100644 index 000000000000..87d4aeaac84f --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml new file mode 100644 index 000000000000..5566ea3f62fc --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml new file mode 100644 index 000000000000..06bb779b91ef --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml new file mode 100644 index 000000000000..15dfcb70e25e --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml new file mode 100644 index 000000000000..3a09284d10a0 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml new file mode 100644 index 000000000000..1d9dacd6c0f9 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable/settingslib_track_selector.xml b/packages/SystemUI/res/drawable/settingslib_track_selector.xml new file mode 100644 index 000000000000..a38c3b4241a3 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_selector.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml new file mode 100644 index 000000000000..aec204f45aa7 --- /dev/null +++ b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/global_actions_toast.xml b/packages/SystemUI/res/layout/global_actions_toast.xml new file mode 100644 index 000000000000..1f0899623ddf --- /dev/null +++ b/packages/SystemUI/res/layout/global_actions_toast.xml @@ -0,0 +1,44 @@ + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml index e4a96947aa6a..6a9254cad8f4 100644 --- a/packages/SystemUI/res/layout/global_screenshot_static.xml +++ b/packages/SystemUI/res/layout/global_screenshot_static.xml @@ -36,7 +36,6 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal" - android:layout_marginBottom="@dimen/screenshot_action_container_offset_y" android:paddingEnd="@dimen/screenshot_action_container_padding_right" android:paddingVertical="@dimen/screenshot_action_container_padding_vertical" android:elevation="1dp" diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml new file mode 100644 index 000000000000..918635d666fa --- /dev/null +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +