Merge sc-qpr1-dev-plus-aosp-without-vendor@7810918

Bug: 205056467
Merged-In: I13199bc39e9445929195f3d15579cbffe94e92b0
Change-Id: I35fa3c6c2abf679c51033f1395a08d511ed8739f
This commit is contained in:
Xin Li 2021-11-18 17:00:37 +00:00
commit 10d9972786
648 changed files with 21734 additions and 5409 deletions

View File

@ -2918,6 +2918,13 @@ public class DeviceIdleController extends SystemService
reasonCode, reason).sendToTarget(); reasonCode, reason).sendToTarget();
} }
reportTempWhitelistChangedLocked(uid, true); 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) { if (informWhitelistChanged) {
@ -3941,6 +3948,10 @@ public class DeviceIdleController extends SystemService
if (idleUntil) { if (idleUntil) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP, mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); 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 { } else {
if (mConstants.USE_WINDOW_ALARMS) { if (mConstants.USE_WINDOW_ALARMS) {
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,

View File

@ -71,7 +71,7 @@ cc_library_shared {
"libui", "libui",
"libjnigraphics", "libjnigraphics",
"libEGL", "libEGL",
"libGLESv1_CM", "libGLESv2",
"libgui", "libgui",
], ],
} }

View File

@ -52,9 +52,8 @@
#include <gui/DisplayEventReceiver.h> #include <gui/DisplayEventReceiver.h>
#include <gui/Surface.h> #include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h> #include <gui/SurfaceComposerClient.h>
#include <GLES2/gl2.h>
#include <GLES/gl.h> #include <GLES2/gl2ext.h>
#include <GLES/glext.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include "BootAnimation.h" #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 char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1; static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
static constexpr size_t TEXT_POS_LEN_MAX = 16; 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<IBinder>&) {
requestExit(); 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* decoder = nullptr;
AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder); AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
if (!decoder) { if (!decoder) {
@ -177,6 +264,10 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
outInfo->stride = AImageDecoder_getMinimumStride(decoder); outInfo->stride = AImageDecoder_getMinimumStride(decoder);
outInfo->flags = 0; outInfo->flags = 0;
if (!premultiplyAlpha) {
AImageDecoder_setUnpremultipliedRequired(decoder, true);
}
const size_t size = outInfo->stride * outInfo->height; const size_t size = outInfo->stride * outInfo->height;
void* pixels = malloc(size); void* pixels = malloc(size);
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, 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, status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const char* name) { const char* name, bool premultiplyAlpha) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
if (asset == nullptr) if (asset == nullptr)
return NO_INIT; return NO_INIT;
AndroidBitmapInfo bitmapInfo; 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<void, decltype(free)*>{ pixels, free }; auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
asset->close(); asset->close();
@ -209,7 +301,6 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const int w = bitmapInfo.width; const int w = bitmapInfo.width;
const int h = bitmapInfo.height; const int h = bitmapInfo.height;
GLint crop[4] = { 0, h, w, -h };
texture->w = w; texture->w = w;
texture->h = h; texture->h = h;
@ -237,18 +328,19 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
break; break;
} }
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
return NO_ERROR; 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; AndroidBitmapInfo bitmapInfo;
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo); void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
premultiplyAlpha);
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free }; auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
// FileMap memory is never released until application exit. // 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 w = bitmapInfo.width;
const int h = bitmapInfo.height; const int h = bitmapInfo.height;
GLint crop[4] = { 0, h, w, -h };
int tw = 1 << (31 - __builtin_clz(w)); int tw = 1 << (31 - __builtin_clz(w));
int th = 1 << (31 - __builtin_clz(h)); int th = 1 << (31 - __builtin_clz(h));
if (tw < w) tw <<= 1; if (tw < w) tw <<= 1;
@ -297,7 +388,10 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
break; 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; *width = w;
*height = h; *height = h;
@ -470,7 +564,9 @@ status_t BootAnimation::readyToRun() {
eglInitialize(display, nullptr, nullptr); eglInitialize(display, nullptr, nullptr);
EGLConfig config = getEglConfig(display); EGLConfig config = getEglConfig(display);
EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr); 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; EGLint w, h;
eglQuerySurface(display, surface, EGL_WIDTH, &w); eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h); eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@ -503,11 +599,6 @@ status_t BootAnimation::readyToRun() {
void BootAnimation::projectSceneToWindow() { void BootAnimation::projectSceneToWindow() {
glViewport(0, 0, mWidth, mHeight); glViewport(0, 0, mWidth, mHeight);
glScissor(0, 0, mWidth, mHeight); glScissor(0, 0, mWidth, mHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
} }
void BootAnimation::resizeSurface(int newWidth, int newHeight) { 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<GLchar> 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 BootAnimation::threadLoop() {
bool result; bool result;
initShaders();
// We have no bootanimation file, so we use the stock android logo // We have no bootanimation file, so we use the stock android logo
// animation. // animation.
if (mZipFileName.isEmpty()) { if (mZipFileName.isEmpty()) {
@ -623,6 +782,8 @@ bool BootAnimation::threadLoop() {
} }
bool BootAnimation::android() { bool BootAnimation::android() {
glActiveTexture(GL_TEXTURE0);
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
elapsedRealtime()); elapsedRealtime());
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
@ -631,19 +792,16 @@ bool BootAnimation::android() {
mCallbacks->init({}); mCallbacks->init({});
// clear screen // clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER); glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glUseProgram(mImageShader);
glClearColor(0,0,0,1); glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface); eglSwapBuffers(mDisplay, mSurface);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// Blend state // Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const nsecs_t startTime = systemTime(); const nsecs_t startTime = systemTime();
do { do {
@ -666,12 +824,12 @@ bool BootAnimation::android() {
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h); drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h);
glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h); drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name); 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); EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE) if (res == EGL_FALSE)
@ -766,6 +924,20 @@ static bool parseColor(const char str[7], float color[3]) {
return true; 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) { static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
ZipEntryRO entry = zip->findEntryByName(name); 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); status = initTexture(font->map, &font->texture.w, &font->texture.h);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else if (fallback != nullptr) { } else if (fallback != nullptr) {
status = initTexture(&font->texture, mAssets, fallback); status = initTexture(&font->texture, mAssets, fallback);
} else { } else {
@ -816,40 +988,11 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
return status; 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<float>(fadedFramesCount) / part.framesToFadeCount;
glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha);
const float frameStartX = static_cast<float>(frameLeft);
const float frameStartY = static_cast<float>(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) { 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 glEnable(GL_BLEND); // Allow us to draw on top of the animation
glBindTexture(GL_TEXTURE_2D, font.texture.name); glBindTexture(GL_TEXTURE_2D, font.texture.name);
glUseProgram(mTextShader);
glUniform1i(mTextTextureLocation, 0);
const int len = strlen(str); const int len = strlen(str);
const int strWidth = font.char_width * len; 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; *y = mHeight + *y - font.char_height;
} }
int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
char c = str[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 charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters
const int row = charPos / FONT_NUM_COLS; const int row = charPos / FONT_NUM_COLS;
const int col = charPos % FONT_NUM_COLS; const int col = charPos % FONT_NUM_COLS;
cropRect[0] = col * font.char_width; // Left of column // Bold fonts are expected in the second half of each row.
cropRect[1] = row * font.char_height * 2; // Top of row float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS;
// Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line float u0 = ((float)col) / FONT_NUM_COLS;
cropRect[1] += bold ? 2 * font.char_height : font.char_height; float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); float u1 = u0 + 1.0f / FONT_NUM_COLS;
glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height); drawTexturedQuad(*x, *y, font.char_width, font.char_height);
*x += font.char_width; *x += font.char_width;
} }
@ -938,6 +1079,8 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
return false; return false;
} }
char const* s = desString.string(); char const* s = desString.string();
std::string dynamicColoringPartName = "";
bool postDynamicColoring = false;
// Parse the description file // Parse the description file
for (;;) { for (;;) {
@ -952,11 +1095,19 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
int pause = 0; int pause = 0;
int progress = 0; int progress = 0;
int framesToFadeCount = 0; int framesToFadeCount = 0;
int colorTransitionStart = 0;
int colorTransitionEnd = 0;
char path[ANIM_ENTRY_NAME_MAX]; char path[ANIM_ENTRY_NAME_MAX];
char color[7] = "000000"; // default to black if unspecified char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = ""; char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = ""; char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
char pathType; 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; int nextReadPos;
@ -971,6 +1122,18 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
} else { } else {
animation.progressEnabled = false; 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", } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
&pathType, &count, &pause, path, &nextReadPos) >= 4) { &pathType, &count, &pause, path, &nextReadPos) >= 4) {
if (pathType == 'f') { if (pathType == 'f') {
@ -983,6 +1146,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
// "clockPos1=%s, clockPos2=%s", // "clockPos1=%s, clockPos2=%s",
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2); // pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
Animation::Part part; 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.playUntilComplete = pathType == 'c';
part.framesToFadeCount = framesToFadeCount; part.framesToFadeCount = framesToFadeCount;
part.count = count; part.count = count;
@ -1166,19 +1339,16 @@ bool BootAnimation::movie() {
// Blend required to draw time on top of animation frames. // Blend required to draw time on top of animation frames.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glDisable(GL_DITHER); glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, 0);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
bool clockFontInitialized = false; bool clockFontInitialized = false;
if (mClockEnabled) { if (mClockEnabled) {
clockFontInitialized = clockFontInitialized =
@ -1193,6 +1363,10 @@ bool BootAnimation::movie() {
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL); mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
} }
if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) {
initDynamicColors();
}
playAnimation(*mAnimation); playAnimation(*mAnimation);
if (mTimeCheckThread != nullptr) { if (mTimeCheckThread != nullptr) {
@ -1218,6 +1392,55 @@ bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part,
(lastDisplayedProgress == 0 || lastDisplayedProgress == 100); (lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
} }
// Linear mapping from range <a1, a2> to range <b1, b2>
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) { bool BootAnimation::playAnimation(const Animation& animation) {
const size_t pcount = animation.parts.size(); const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps; nsecs_t frameDuration = s2ns(1) / animation.fps;
@ -1230,7 +1453,6 @@ bool BootAnimation::playAnimation(const Animation& animation) {
for (size_t i=0 ; i<pcount ; i++) { for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]); const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size(); const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
// Handle animation package // Handle animation package
if (part.animation != nullptr) { if (part.animation != nullptr) {
@ -1261,6 +1483,19 @@ bool BootAnimation::playAnimation(const Animation& animation) {
for (size_t j=0 ; j<fcount ; j++) { for (size_t j=0 ; j<fcount ; j++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break; if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
// Color progress is
// - the animation progress, normalized from
// [colorTransitionStart,colorTransitionEnd] to [0, 1] for the dynamic coloring
// part.
// - 0 for parts that come before,
// - 1 for parts that come after.
float colorProgress = part.useDynamicColoring
? fmin(fmax(
((float)j - animation.colorTransitionStart) /
fmax(animation.colorTransitionEnd -
animation.colorTransitionStart, 1.0f), 0.0f), 1.0f)
: (part.postDynamicColoring ? 1 : 0);
processDisplayEvents(); processDisplayEvents();
const int animationX = (mWidth - animation.width) / 2; const int animationX = (mWidth - animation.width) / 2;
@ -1272,44 +1507,38 @@ bool BootAnimation::playAnimation(const Animation& animation) {
if (r > 0) { if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid); glBindTexture(GL_TEXTURE_2D, frame.tid);
} else { } else {
if (part.count != 1) { glGenTextures(1, &frame.tid);
glGenTextures(1, &frame.tid); glBindTexture(GL_TEXTURE_2D, 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);
}
int w, h; 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 xc = animationX + frame.trimX;
const int yc = animationY + frame.trimY; const int yc = animationY + frame.trimY;
Region clearReg(Rect(mWidth, mHeight)); glClear(GL_COLOR_BUFFER_BIT);
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);
}
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2) // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight) // which is equivalent to mHeight - (yc + frame.trimHeight)
const int frameDrawY = 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 the part hasn't been stopped yet then continue fading if necessary
if (exitPending() && part.hasFadingPhase()) { if (exitPending() && part.hasFadingPhase()) {
fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part, fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount;
++fadedFramesCount);
if (fadedFramesCount >= part.framesToFadeCount) { if (fadedFramesCount >= part.framesToFadeCount) {
fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading 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)) { if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY); drawClock(animation.clockFont, part.clockPosX, part.clockPosY);

View File

@ -31,7 +31,7 @@
#include <binder/IBinder.h> #include <binder/IBinder.h>
#include <EGL/egl.h> #include <EGL/egl.h>
#include <GLES/gl.h> #include <GLES2/gl2.h>
namespace android { namespace android {
@ -53,7 +53,7 @@ public:
}; };
struct Font { struct Font {
FileMap* map; FileMap* map = nullptr;
Texture texture; Texture texture;
int char_width; int char_width;
int char_height; int char_height;
@ -62,7 +62,7 @@ public:
struct Animation { struct Animation {
struct Frame { struct Frame {
String8 name; String8 name;
FileMap* map; FileMap* map = nullptr;
int trimX; int trimX;
int trimY; int trimY;
int trimWidth; int trimWidth;
@ -90,6 +90,10 @@ public:
uint8_t* audioData; uint8_t* audioData;
int audioLength; int audioLength;
Animation* animation; 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 { bool hasFadingPhase() const {
return !playUntilComplete && framesToFadeCount > 0; return !playUntilComplete && framesToFadeCount > 0;
@ -105,6 +109,12 @@ public:
ZipFileRO* zip; ZipFileRO* zip;
Font clockFont; Font clockFont;
Font progressFont; 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. // All callbacks will be called from this class's internal thread.
@ -163,9 +173,12 @@ private:
int displayEventCallback(int fd, int events, void* data); int displayEventCallback(int fd, int events, void* data);
void processDisplayEvents(); void processDisplayEvents();
status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(Texture* texture, AssetManager& asset, const char* name,
status_t initTexture(FileMap* map, int* width, int* height); bool premultiplyAlpha = true);
status_t initTexture(FileMap* map, int* width, int* height,
bool premultiplyAlpha = true);
status_t initFont(Font* font, const char* fallback); status_t initFont(Font* font, const char* fallback);
void initShaders();
bool android(); bool android();
bool movie(); bool movie();
void drawText(const char* str, const Font& font, bool bold, int* x, int* y); 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 drawProgress(int percent, const Font& font, const int xPos, const int yPos);
void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight, void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
const Animation::Part& part, int fadedFramesCount); const Animation::Part& part, int fadedFramesCount);
void drawTexturedQuad(float xStart, float yStart, float width, float height);
bool validClock(const Animation::Part& part); bool validClock(const Animation::Part& part);
Animation* loadAnimation(const String8&); Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&); bool playAnimation(const Animation&);
@ -192,6 +206,7 @@ private:
void checkExit(); void checkExit();
void handleViewport(nsecs_t timestep); void handleViewport(nsecs_t timestep);
void initDynamicColors();
sp<SurfaceComposerClient> mSession; sp<SurfaceComposerClient> mSession;
AssetManager mAssets; AssetManager mAssets;
@ -218,6 +233,13 @@ private:
sp<TimeCheckThread> mTimeCheckThread = nullptr; sp<TimeCheckThread> mTimeCheckThread = nullptr;
sp<Callbacks> mCallbacks; sp<Callbacks> mCallbacks;
Animation* mAnimation = nullptr; Animation* mAnimation = nullptr;
GLuint mImageShader;
GLuint mTextShader;
GLuint mImageFadeLocation;
GLuint mImageTextureLocation;
GLuint mTextCropAreaLocation;
GLuint mTextTextureLocation;
GLuint mImageColorProgressLocation;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,4 +1,3 @@
set noparent set noparent
toddke@google.com
patb@google.com patb@google.com
zyy@google.com zyy@google.com

View File

@ -771,6 +771,11 @@ public class ActivityManager {
return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND; 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? */ /** @hide Is this a foreground service type? */
public static boolean isForegroundService(int procState) { public static boolean isForegroundService(int procState) {
return procState == PROCESS_STATE_FOREGROUND_SERVICE; return procState == PROCESS_STATE_FOREGROUND_SERVICE;

View File

@ -156,6 +156,7 @@ public abstract class ActivityManagerInternal {
/** /**
* Update information about which app IDs are on the temp allowlist. * Update information about which app IDs are on the temp allowlist.
* @param appids the updated list of appIds in 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 changingUid uid to add or remove to temp allowlist.
* @param adding true to add to temp allowlist, false to remove from 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. * @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 * @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
* is true. * 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, boolean adding, long durationMs, @TempAllowListType int type,
@ReasonCode int reasonCode, @ReasonCode int reasonCode,
@Nullable String reason, int callingUid); @Nullable String reason, int callingUid);

View File

@ -4906,7 +4906,8 @@ public final class ActivityThread extends ClientTransactionHandler
Slog.w(TAG, "Activity top position already set to onTop=" + onTop); Slog.w(TAG, "Activity top position already set to onTop=" + onTop);
return; 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; r.isTopResumedActivity = onTop;

View File

@ -2735,10 +2735,13 @@ class ContextImpl extends Context {
// need to override their display in ResourcesManager. // need to override their display in ResourcesManager.
baseContext.mForceDisplayOverrideInResources = false; baseContext.mForceDisplayOverrideInResources = false;
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT; baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
baseContext.mDisplay = display;
final Resources windowContextResources = createWindowContextResources(baseContext); final Resources windowContextResources = createWindowContextResources(baseContext);
baseContext.setResources(windowContextResources); 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; return baseContext;
} }

View File

@ -135,6 +135,7 @@ public final class GameManager {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
/** /**
* Returns a list of supported game modes for a given package. * Returns a list of supported game modes for a given package.
* <p> * <p>
@ -151,4 +152,20 @@ public final class GameManager {
} }
} }
/**
* Returns if ANGLE is enabled for a given package.
* <p>
* 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();
}
}
} }

View File

@ -23,4 +23,5 @@ interface IGameManagerService {
int getGameMode(String packageName, int userId); int getGameMode(String packageName, int userId);
void setGameMode(String packageName, int gameMode, int userId); void setGameMode(String packageName, int gameMode, int userId);
int[] getAvailableGameModes(String packageName); int[] getAvailableGameModes(String packageName);
boolean getAngleEnabled(String packageName, int userId);
} }

View File

@ -1884,6 +1884,14 @@ public class Notification implements Parcelable
* clicks. To launch an activity in those cases, provide a {@link PendingIntent} for the * clicks. To launch an activity in those cases, provide a {@link PendingIntent} for the
* activity itself. * activity itself.
* *
* <p>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.
*
* <p>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 icon icon to show for this action
* @param title the title of the action * @param title the title of the action
* @param intent the {@link PendingIntent} to fire when users trigger this 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); contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
// Use different highlighted colors for conversations' unread count // Use different highlighted colors for conversations' unread count
if (p.mHighlightExpander) { if (p.mHighlightExpander) {
pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor); pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
textColor = Colors.flattenAlpha(bgColor, pillColor); textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor);
} }
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor); contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor); contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@ -6121,21 +6129,22 @@ public class Notification implements Parcelable
if (emphasizedMode) { if (emphasizedMode) {
// change the background bgColor // change the background bgColor
CharSequence title = action.title; CharSequence title = action.title;
ColorStateList[] outResultColor = new ColorStateList[1];
int buttonFillColor = getColors(p).getSecondaryAccentColor(); int buttonFillColor = getColors(p).getSecondaryAccentColor();
if (isLegacy()) { if (isLegacy()) {
title = ContrastColorUtil.clearColorSpans(title); title = ContrastColorUtil.clearColorSpans(title);
} else { } else {
int notifBackgroundColor = getColors(p).getBackgroundColor(); // Check for a full-length span color to use as the button fill color.
title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor); 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)); 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, final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
buttonFillColor, mInNightMode); buttonFillColor, mInNightMode);
button.setTextColor(R.id.action0, textColor); 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 * Extract the color from a full-length span from the text.
* text if a span was found that spans over the whole 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 charSequence the charSequence on which the spans are
* @param background the background color to ensure the contrast against * @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 * @return the contrasted charSequence
* @hide
*/ */
private static CharSequence ensureColorSpanContrast(CharSequence charSequence, @VisibleForTesting
int background, ColorStateList[] outResultColor) { public static CharSequence ensureColorSpanContrast(CharSequence charSequence,
int background) {
if (charSequence instanceof Spanned) { if (charSequence instanceof Spanned) {
Spanned ss = (Spanned) charSequence; Spanned ss = (Spanned) charSequence;
Object[] spans = ss.getSpans(0, ss.length(), Object.class); Object[] spans = ss.getSpans(0, ss.length(), Object.class);
@ -6195,19 +6245,19 @@ public class Notification implements Parcelable
TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
ColorStateList textColor = originalSpan.getTextColor(); ColorStateList textColor = originalSpan.getTextColor();
if (textColor != null) { 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) { if (fullLength) {
outResultColor[0] = textColor;
// Let's drop the color from the span // Let's drop the color from the span
textColor = null; 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( resultSpan = new TextAppearanceSpan(
originalSpan.getFamily(), originalSpan.getFamily(),
@ -6217,15 +6267,14 @@ public class Notification implements Parcelable
originalSpan.getLinkTextColor()); originalSpan.getLinkTextColor());
} }
} else if (resultSpan instanceof ForegroundColorSpan) { } 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) { if (fullLength) {
outResultColor[0] = ColorStateList.valueOf(foregroundColor);
resultSpan = null; resultSpan = null;
} else { } else {
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
int foregroundColor = originalSpan.getForegroundColor();
boolean isBgDark = isColorDark(background);
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
foregroundColor, background, isBgDark);
resultSpan = new ForegroundColorSpan(foregroundColor); resultSpan = new ForegroundColorSpan(foregroundColor);
} }
} else { } else {
@ -6247,12 +6296,28 @@ public class Notification implements Parcelable
* *
* @param color the color to check * @param color the color to check
* @return true if the color has higher contrast with white than black * @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. // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474; 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 * @return Whether we are currently building a notification from a legacy (an app that
* doesn't create material notifications by itself) app. * 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 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
&& !styleDisplaysCustomViewInline()) { && !styleDisplaysCustomViewInline()) {
if (mN.contentView == null) { RemoteViews newContentView = mN.contentView;
mN.contentView = createContentView(); RemoteViews newBigContentView = mN.bigContentView;
RemoteViews newHeadsUpContentView = mN.headsUpContentView;
if (newContentView == null) {
newContentView = createContentView();
mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
mN.contentView.getSequenceNumber()); newContentView.getSequenceNumber());
} }
if (mN.bigContentView == null) { if (newBigContentView == null) {
mN.bigContentView = createBigContentView(); newBigContentView = createBigContentView();
if (mN.bigContentView != null) { if (newBigContentView != null) {
mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
mN.bigContentView.getSequenceNumber()); newBigContentView.getSequenceNumber());
} }
} }
if (mN.headsUpContentView == null) { if (newHeadsUpContentView == null) {
mN.headsUpContentView = createHeadsUpContentView(); newHeadsUpContentView = createHeadsUpContentView();
if (mN.headsUpContentView != null) { if (newHeadsUpContentView != null) {
mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, 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) { if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
@ -12305,6 +12379,8 @@ public class Notification implements Parcelable
private int mSecondaryTextColor = COLOR_INVALID; private int mSecondaryTextColor = COLOR_INVALID;
private int mPrimaryAccentColor = COLOR_INVALID; private int mPrimaryAccentColor = COLOR_INVALID;
private int mSecondaryAccentColor = COLOR_INVALID; private int mSecondaryAccentColor = COLOR_INVALID;
private int mTertiaryAccentColor = COLOR_INVALID;
private int mOnAccentTextColor = COLOR_INVALID;
private int mErrorColor = COLOR_INVALID; private int mErrorColor = COLOR_INVALID;
private int mContrastColor = COLOR_INVALID; private int mContrastColor = COLOR_INVALID;
private int mRippleAlpha = 0x33; private int mRippleAlpha = 0x33;
@ -12362,7 +12438,7 @@ public class Notification implements Parcelable
if (isColorized) { if (isColorized) {
if (rawColor == COLOR_DEFAULT) { if (rawColor == COLOR_DEFAULT) {
int[] attrs = {R.attr.colorAccentTertiary}; int[] attrs = {R.attr.colorAccentSecondary};
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
mBackgroundColor = getColor(ta, 0, Color.WHITE); mBackgroundColor = getColor(ta, 0, Color.WHITE);
} }
@ -12379,6 +12455,8 @@ public class Notification implements Parcelable
mContrastColor = mPrimaryTextColor; mContrastColor = mPrimaryTextColor;
mPrimaryAccentColor = mPrimaryTextColor; mPrimaryAccentColor = mPrimaryTextColor;
mSecondaryAccentColor = mSecondaryTextColor; mSecondaryAccentColor = mSecondaryTextColor;
mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
mOnAccentTextColor = mBackgroundColor;
mErrorColor = mPrimaryTextColor; mErrorColor = mPrimaryTextColor;
mRippleAlpha = 0x33; mRippleAlpha = 0x33;
} else { } else {
@ -12389,6 +12467,8 @@ public class Notification implements Parcelable
R.attr.textColorSecondary, R.attr.textColorSecondary,
R.attr.colorAccent, R.attr.colorAccent,
R.attr.colorAccentSecondary, R.attr.colorAccentSecondary,
R.attr.colorAccentTertiary,
R.attr.textColorOnAccent,
R.attr.colorError, R.attr.colorError,
R.attr.colorControlHighlight R.attr.colorControlHighlight
}; };
@ -12399,8 +12479,10 @@ public class Notification implements Parcelable
mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID); mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID); mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID); mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
mErrorColor = getColor(ta, 6, COLOR_INVALID); mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff)); mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
mErrorColor = getColor(ta, 8, COLOR_INVALID);
mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
} }
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor, mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
mBackgroundColor, nightMode); mBackgroundColor, nightMode);
@ -12420,6 +12502,14 @@ public class Notification implements Parcelable
if (mSecondaryAccentColor == COLOR_INVALID) { if (mSecondaryAccentColor == COLOR_INVALID) {
mSecondaryAccentColor = mContrastColor; 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) { if (mErrorColor == COLOR_INVALID) {
mErrorColor = mPrimaryTextColor; mErrorColor = mPrimaryTextColor;
} }
@ -12485,6 +12575,16 @@ public class Notification implements Parcelable
return mSecondaryAccentColor; 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 * @return the contrast-adjusted version of the color provided by the app, or the
* primary text color when colorized. * primary text color when colorized.

View File

@ -260,8 +260,6 @@ public final class NotificationChannel implements Parcelable {
private boolean mDemoted = false; private boolean mDemoted = false;
private boolean mImportantConvo = false; private boolean mImportantConvo = false;
private long mDeletedTime = DEFAULT_DELETION_TIME_MS; 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. * Creates a notification channel.
@ -716,13 +714,6 @@ public final class NotificationChannel implements Parcelable {
return mSound; return mSound;
} }
/**
* @hide
*/
public boolean isSoundMissing() {
return mIsSoundMissing;
}
/** /**
* Returns the audio attributes for sound played by notifications posted to this channel. * 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. // according to the docs because canonicalize method has to handle canonical uris as well.
Uri canonicalizedUri = contentResolver.canonicalize(uri); Uri canonicalizedUri = contentResolver.canonicalize(uri);
if (canonicalizedUri == null) { if (canonicalizedUri == null) {
// We got a null because the uri in the backup does not exist here. // We got a null because the uri in the backup does not exist here, so we return default
mIsSoundMissing = true; return Settings.System.DEFAULT_NOTIFICATION_URI;
return null;
} }
return contentResolver.uncanonicalize(canonicalizedUri); return contentResolver.uncanonicalize(canonicalizedUri);
} }

View File

@ -559,6 +559,53 @@ public class WallpaperManager {
return null; 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() { void forgetLoadedWallpaper() {
synchronized (this) { synchronized (this) {
mCachedWallpaper = null; mCachedWallpaper = null;
@ -1038,6 +1085,17 @@ public class WallpaperManager {
return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy); 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. * 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. * The caller is responsible for closing the file descriptor when done ingesting the file.

View File

@ -9733,6 +9733,27 @@ public class DevicePolicyManager {
return null; 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 * 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 * actual package file remain. This function can be called by a device owner, profile owner, or

View File

@ -251,6 +251,7 @@ interface IDevicePolicyManager {
boolean isNotificationListenerServicePermitted(in String packageName, int userId); boolean isNotificationListenerServicePermitted(in String packageName, int userId);
Intent createAdminSupportIntent(in String restriction); 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 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); boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent);

View File

@ -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.
* <p>
* 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 * @deprecated Applications shouldn't request a restore operation using this method. In Android
* P and later, this method is a no-op. * P and later, this method is a no-op.

View File

@ -70,7 +70,7 @@ public final class Query implements Parcelable {
@NonNull Bundle extras) { @NonNull Bundle extras) {
mInput = input; mInput = input;
mTimestampMillis = timestampMillis; mTimestampMillis = timestampMillis;
mExtras = extras == null ? extras : new Bundle(); mExtras = extras != null ? extras : new Bundle();
} }
/** /**

View File

@ -143,7 +143,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public ComponentName provider; 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. * at least this width, and will often be given more, depending on the host.
* *
* <p>This field corresponds to the <code>android:minWidth</code> attribute in * <p>This field corresponds to the <code>android:minWidth</code> attribute in
@ -152,7 +152,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minWidth; 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. * at least this height, and will often be given more, depending on the host.
* *
* <p>This field corresponds to the <code>android:minHeight</code> attribute in * <p>This field corresponds to the <code>android:minHeight</code> attribute in
@ -161,7 +161,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minHeight; 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}). * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
* *
* <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in * <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
@ -170,7 +170,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minResizeWidth; 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}). * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
* *
* <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in * <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
@ -179,7 +179,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minResizeHeight; 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}). * smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
* *
* <p>This field corresponds to the <code>android:maxResizeWidth</code> attribute in the * <p>This field corresponds to the <code>android:maxResizeWidth</code> attribute in the
@ -189,7 +189,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int maxResizeWidth; 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}). * smaller than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
* *
* <p>This field corresponds to the <code>android:maxResizeHeight</code> attribute in the * <p>This field corresponds to the <code>android:maxResizeHeight</code> attribute in the

View File

@ -3286,7 +3286,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O} * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O}
* or higher are not allowed to start background services from the background. * or higher are not allowed to start background services from the background.
* See * See
* <a href="{@docRoot}/about/versions/oreo/background"> * <a href="/about/versions/oreo/background">
* Background Execution Limits</a> * Background Execution Limits</a>
* for more details. * for more details.
* *
@ -3295,7 +3295,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background. * or higher are not allowed to start foreground services from the background.
* See * See
* <a href="{@docRoot}/about/versions/12/behavior-changes-12"> * <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12 * Behavior changes: Apps targeting Android 12
* </a> * </a>
* for more details. * for more details.
@ -3349,7 +3349,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background. * or higher are not allowed to start foreground services from the background.
* See * See
* <a href="{@docRoot}/about/versions/12/behavior-changes-12"> * <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12 * Behavior changes: Apps targeting Android 12
* </a> * </a>
* for more details. * for more details.
@ -6026,6 +6026,10 @@ public abstract class Context {
* more general access to the URI's content provider then this check will * more general access to the URI's content provider then this check will
* always fail. * always fail.
* *
* <strong>Note:</strong> 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 uris The list of URIs that is being checked.
* @param pid The process ID being checked against. Must be &gt; 0. * @param pid The process ID being checked against. Must be &gt; 0.
* @param uid The user ID being checked against. A uid of 0 is the root * @param uid The user ID being checked against. A uid of 0 is the root

View File

@ -2742,6 +2742,22 @@ public class Intent implements Parcelable, Cloneable {
*/ */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED"; 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.
* <p>Includes the following extras:
* <ul>
* <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been modified
* <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been modified
* </ul>
*
* <p class="note">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. * Broadcast Action: Distracting packages have been changed.

View File

@ -1,5 +1,3 @@
# Bug component: 722021 # Bug component: 722021
toddke@android.com
toddke@google.com
patb@google.com patb@google.com

View File

@ -1,6 +1,4 @@
# Bug component: 568631 # Bug component: 568631
toddke@android.com
toddke@google.com
patb@google.com patb@google.com
zyy@google.com zyy@google.com

View File

@ -1,11 +1,9 @@
# Bug component: 36137 # Bug component: 36137
toddke@android.com
toddke@google.com
patb@google.com patb@google.com
per-file PackageParser.java = set noparent 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 *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file AppSearchPerson.java = 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 per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS

View File

@ -1,7 +1,5 @@
# Bug component: 86431 # Bug component: 86431
toddke@android.com
toddke@google.com
patb@google.com patb@google.com
calin@google.com calin@google.com
ngeoffray@google.com ngeoffray@google.com

View File

@ -2,4 +2,3 @@
chiuwinson@google.com chiuwinson@google.com
patb@google.com patb@google.com
toddke@google.com

View File

@ -2,7 +2,5 @@
include platform/frameworks/base:/core/java/android/permission/OWNERS include platform/frameworks/base:/core/java/android/permission/OWNERS
toddke@android.com
toddke@google.com
patb@google.com patb@google.com

View File

@ -1,5 +1,3 @@
# Bug component: 36137 # Bug component: 36137
toddke@android.com
toddke@google.com
patb@google.com patb@google.com

View File

@ -2,4 +2,3 @@
chiuwinson@google.com chiuwinson@google.com
patb@google.com patb@google.com
toddke@google.com

View File

@ -1,6 +1,4 @@
# Bug component: 568761 # Bug component: 568761
toddke@android.com
toddke@google.com
patb@google.com patb@google.com
zyy@google.com zyy@google.com

View File

@ -1,5 +1,5 @@
# Camera # 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 # Sensor Privacy
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS

View File

@ -438,9 +438,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
} }
private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener { private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
private final long mAuthRequestId;
OnAuthenticationCancelListener(long id) {
mAuthRequestId = id;
}
@Override @Override
public void onCancel() { 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 userId The user to authenticate
* @param operationId The keystore operation associated with authentication * @param operationId The keystore operation associated with authentication
* *
* @return A requestId that can be used to cancel this operation.
*
* @hide * @hide
*/ */
@RequiresPermission(USE_BIOMETRIC_INTERNAL) @RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticateUserForOperation( public long authenticateUserForOperation(
@NonNull CancellationSignal cancel, @NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor, @NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback, @NonNull AuthenticationCallback callback,
@ -871,7 +880,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
if (callback == null) { if (callback == null) {
throw new IllegalArgumentException("Must supply a callback"); 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()); authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
} }
private void cancelAuthentication() { private void cancelAuthentication(long requestId) {
if (mService != null) { if (mService != null) {
try { try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName()); mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Unable to cancel authentication", 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); authenticateInternal(operationId, cancel, executor, callback, userId);
} }
private void authenticateInternal( private long authenticateInternal(
long operationId, long operationId,
@NonNull CancellationSignal cancel, @NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor, @NonNull @CallbackExecutor Executor executor,
@ -1040,9 +1050,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
try { try {
if (cancel.isCanceled()) { if (cancel.isCanceled()) {
Log.w(TAG, "Authentication already canceled"); Log.w(TAG, "Authentication already canceled");
return; return -1;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener());
} }
mExecutor = executor; mExecutor = executor;
@ -1065,14 +1073,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
promptInfo = mPromptInfo; promptInfo = mPromptInfo;
} }
mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, final long authId = mService.authenticate(mToken, operationId, userId,
mContext.getOpPackageName(), promptInfo); mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo);
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
return authId;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e); Log.e(TAG, "Remote exception while authenticating", e);
mExecutor.execute(() -> callback.onAuthenticationError( mExecutor.execute(() -> callback.onAuthenticationError(
BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
mContext.getString(R.string.biometric_error_hw_unavailable))); mContext.getString(R.string.biometric_error_hw_unavailable)));
return -1;
} }
} }

View File

@ -41,13 +41,14 @@ interface IAuthService {
// Retrieve the package where BIometricOrompt's UI is implemented // Retrieve the package where BIometricOrompt's UI is implemented
String getUiPackage(); String getUiPackage();
// Requests authentication. The service choose the appropriate biometric to use, and show // Requests authentication. The service chooses the appropriate biometric to use, and shows
// the corresponding BiometricDialog. // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
void authenticate(IBinder token, long sessionId, int userId, // this operation.
long authenticate(IBinder token, long sessionId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
// Cancel authentication for the given sessionId // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics. // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
// Checks if biometrics can be used. // Checks if biometrics can be used.

View File

@ -48,13 +48,13 @@ interface IBiometricAuthenticator {
// startPreparedClient(). // startPreparedClient().
void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, boolean allowBackgroundAuthentication); long requestId, int cookie, boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client. // Starts authentication with the previously prepared client.
void startPreparedClient(int cookie); void startPreparedClient(int cookie);
// Cancels authentication. // Cancels authentication for the given requestId.
void cancelAuthenticationFromService(IBinder token, String opPackageName); void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId);
// Determine if HAL is loaded and ready // Determine if HAL is loaded and ready
boolean isHardwareDetected(String opPackageName); boolean isHardwareDetected(String opPackageName);

View File

@ -36,13 +36,14 @@ interface IBiometricService {
// Retrieve static sensor properties for all biometric sensors // Retrieve static sensor properties for all biometric sensors
List<SensorPropertiesInternal> getSensorProperties(String opPackageName); List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
// Requests authentication. The service choose the appropriate biometric to use, and show // Requests authentication. The service chooses the appropriate biometric to use, and shows
// the corresponding BiometricDialog. // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
void authenticate(IBinder token, long operationId, int userId, // this operation.
long authenticate(IBinder token, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
// Cancel authentication for the given session. // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Checks if biometrics can be used. // Checks if biometrics can be used.
int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators); int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);

View File

@ -263,12 +263,12 @@ public final class CameraExtensionCharacteristics {
@Override @Override
public void onServiceConnected(ComponentName component, IBinder binder) { public void onServiceConnected(ComponentName component, IBinder binder) {
mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder); mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder);
mInitFuture.setStatus(true);
try { try {
mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported(); mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Remote IPC failed!"); Log.e(TAG, "Remote IPC failed!");
} }
mInitFuture.setStatus(true);
} }
}; };
ctx.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | ctx.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT |

View File

@ -59,7 +59,7 @@ public class CaptureFailure {
private final CaptureRequest mRequest; private final CaptureRequest mRequest;
private final int mReason; private final int mReason;
private final boolean mDropped; private final boolean mWasImageCaptured;
private final int mSequenceId; private final int mSequenceId;
private final long mFrameNumber; private final long mFrameNumber;
private final String mErrorPhysicalCameraId; private final String mErrorPhysicalCameraId;
@ -68,10 +68,11 @@ public class CaptureFailure {
* @hide * @hide
*/ */
public CaptureFailure(CaptureRequest request, int reason, public CaptureFailure(CaptureRequest request, int reason,
boolean dropped, int sequenceId, long frameNumber, String errorPhysicalCameraId) { boolean wasImageCaptured, int sequenceId, long frameNumber,
String errorPhysicalCameraId) {
mRequest = request; mRequest = request;
mReason = reason; mReason = reason;
mDropped = dropped; mWasImageCaptured = wasImageCaptured;
mSequenceId = sequenceId; mSequenceId = sequenceId;
mFrameNumber = frameNumber; mFrameNumber = frameNumber;
mErrorPhysicalCameraId = errorPhysicalCameraId; mErrorPhysicalCameraId = errorPhysicalCameraId;
@ -141,7 +142,7 @@ public class CaptureFailure {
* @return boolean True if the image was captured, false otherwise. * @return boolean True if the image was captured, false otherwise.
*/ */
public boolean wasImageCaptured() { public boolean wasImageCaptured() {
return !mDropped; return mWasImageCaptured;
} }
/** /**

View File

@ -873,21 +873,19 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override @Override
public int submitBurst(List<Request> requests, IRequestCallback callback) { public int submitBurst(List<Request> requests, IRequestCallback callback) {
int seqId = -1; int seqId = -1;
synchronized (mInterfaceLock) { try {
try { CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback); ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
ArrayList<CaptureRequest> captureRequests = new ArrayList<>(); for (Request request : requests) {
for (Request request : requests) { captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
captureRequests.add(initializeCaptureRequest(mCameraDevice, request, mCameraConfigMap));
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!");
} }
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; return seqId;
@ -896,18 +894,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override @Override
public int setRepeating(Request request, IRequestCallback callback) { public int setRepeating(Request request, IRequestCallback callback) {
int seqId = -1; int seqId = -1;
synchronized (mInterfaceLock) { try {
try { CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice, request, mCameraConfigMap);
request, mCameraConfigMap); CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback); seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest, new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback); } catch (CameraAccessException e) {
} catch (CameraAccessException e) { Log.e(TAG, "Failed to enable repeating request!");
Log.e(TAG, "Failed to enable repeating request!"); } catch (IllegalStateException e) {
} catch (IllegalStateException e) { Log.e(TAG, "Capture session closed!");
Log.e(TAG, "Capture session closed!");
}
} }
return seqId; return seqId;
@ -915,27 +911,23 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override @Override
public void abortCaptures() { public void abortCaptures() {
synchronized (mInterfaceLock) { try {
try { mCaptureSession.abortCaptures();
mCaptureSession.abortCaptures(); } catch (CameraAccessException e) {
} catch (CameraAccessException e) { Log.e(TAG, "Failed during capture abort!");
Log.e(TAG, "Failed during capture abort!"); } catch (IllegalStateException e) {
} catch (IllegalStateException e) { Log.e(TAG, "Capture session closed!");
Log.e(TAG, "Capture session closed!");
}
} }
} }
@Override @Override
public void stopRepeating() { public void stopRepeating() {
synchronized (mInterfaceLock) { try {
try { mCaptureSession.stopRepeating();
mCaptureSession.stopRepeating(); } catch (CameraAccessException e) {
} catch (CameraAccessException e) { Log.e(TAG, "Failed during repeating capture stop!");
Log.e(TAG, "Failed during repeating capture stop!"); } catch (IllegalStateException e) {
} catch (IllegalStateException e) { Log.e(TAG, "Capture session closed!");
Log.e(TAG, "Capture session closed!");
}
} }
} }
} }

View File

@ -104,6 +104,9 @@ public class CameraDeviceImpl extends CameraDevice
private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap = private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
new SparseArray<CaptureCallbackHolder>(); new SparseArray<CaptureCallbackHolder>();
/** map request IDs which have batchedOutputs to requestCount*/
private HashMap<Integer, Integer> mBatchOutputMap = new HashMap<>();
private int mRepeatingRequestId = REQUEST_ID_NONE; private int mRepeatingRequestId = REQUEST_ID_NONE;
// Latest repeating request list's types // Latest repeating request list's types
private int[] mRepeatingRequestTypes; private int[] mRepeatingRequestTypes;
@ -973,6 +976,7 @@ public class CameraDeviceImpl extends CameraDevice
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null); mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null);
mIdle = true; mIdle = true;
mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>(); mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>();
mBatchOutputMap = new HashMap<>();
mFrameNumberTracker = new FrameNumberTracker(); mFrameNumberTracker = new FrameNumberTracker();
mCurrentSession.closeWithoutDraining(); mCurrentSession.closeWithoutDraining();
@ -1179,6 +1183,41 @@ public class CameraDeviceImpl extends CameraDevice
return requestTypes; return requestTypes;
} }
private boolean hasBatchedOutputs(List<CaptureRequest> 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<Surface> 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<CaptureRequest> requestList, CaptureCallback callback, private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Executor executor, boolean repeating) throws CameraAccessException { Executor executor, boolean repeating) throws CameraAccessException {
@ -1224,6 +1263,14 @@ public class CameraDeviceImpl extends CameraDevice
request.recoverStreamIdToSurface(); 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) { if (callback != null) {
mCaptureCallbackMap.put(requestInfo.getRequestId(), mCaptureCallbackMap.put(requestInfo.getRequestId(),
new CaptureCallbackHolder( new CaptureCallbackHolder(
@ -1820,7 +1867,7 @@ public class CameraDeviceImpl extends CameraDevice
final CaptureFailure failure = new CaptureFailure( final CaptureFailure failure = new CaptureFailure(
request, request,
reason, reason,
/*dropped*/ mayHaveBuffers, mayHaveBuffers,
requestId, requestId,
frameNumber, frameNumber,
errorPhysicalCameraId); errorPhysicalCameraId);
@ -1839,8 +1886,18 @@ public class CameraDeviceImpl extends CameraDevice
if (DEBUG) { if (DEBUG) {
Log.v(TAG, String.format("got error frame %d", frameNumber)); 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(); checkAndFireSequenceComplete();
// Dispatch the failure callback // Dispatch the failure callback
@ -2023,7 +2080,6 @@ public class CameraDeviceImpl extends CameraDevice
public void onResultReceived(CameraMetadataNative result, public void onResultReceived(CameraMetadataNative result,
CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[]) CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
throws RemoteException { throws RemoteException {
int requestId = resultExtras.getRequestId(); int requestId = resultExtras.getRequestId();
long frameNumber = resultExtras.getFrameNumber(); long frameNumber = resultExtras.getFrameNumber();
@ -2064,8 +2120,8 @@ public class CameraDeviceImpl extends CameraDevice
+ frameNumber); + frameNumber);
} }
mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult, updateTracker(requestId, frameNumber, requestType, /*result*/null,
requestType); isPartialResult);
return; return;
} }
@ -2077,8 +2133,9 @@ public class CameraDeviceImpl extends CameraDevice
+ frameNumber); + frameNumber);
} }
mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult, updateTracker(requestId, frameNumber, requestType, /*result*/null,
requestType); isPartialResult);
return; return;
} }
@ -2184,9 +2241,7 @@ public class CameraDeviceImpl extends CameraDevice
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
// Collect the partials for a total result; or mark the frame as totally completed updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult);
mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
requestType);
// Fire onCaptureSequenceCompleted // Fire onCaptureSequenceCompleted
if (!isPartialResult) { if (!isPartialResult) {

View File

@ -58,7 +58,7 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
private static final class JpegParameters { private static final class JpegParameters {
public HashSet<Long> mTimeStamps = new HashSet<>(); public HashSet<Long> 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] public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100]
} }
@ -100,7 +100,8 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
Integer orientation = captureBundles.get(0).captureResult.get( Integer orientation = captureBundles.get(0).captureResult.get(
CaptureResult.JPEG_ORIENTATION); CaptureResult.JPEG_ORIENTATION);
if (orientation != null) { if (orientation != null) {
ret.mRotation = orientation / 90; // The jpeg encoder expects CCW rotation, convert from CW
ret.mRotation = (360 - (orientation % 360)) / 90;
} else { } else {
Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION); Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION);
} }

View File

@ -60,12 +60,18 @@ public final class BrightnessInfo implements Parcelable {
/** Brightness */ /** Brightness */
public final float brightness; public final float brightness;
/** Brightness after {@link DisplayPowerController} adjustments */
public final float adjustedBrightness;
/** Current minimum supported brightness. */ /** Current minimum supported brightness. */
public final float brightnessMinimum; public final float brightnessMinimum;
/** Current maximum supported brightness. */ /** Current maximum supported brightness. */
public final float brightnessMaximum; 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. * Current state of high brightness mode.
* Can be any of HIGH_BRIGHTNESS_MODE_* values. * Can be any of HIGH_BRIGHTNESS_MODE_* values.
@ -73,11 +79,20 @@ public final class BrightnessInfo implements Parcelable {
public final int highBrightnessMode; public final int highBrightnessMode;
public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum, 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.brightness = brightness;
this.adjustedBrightness = adjustedBrightness;
this.brightnessMinimum = brightnessMinimum; this.brightnessMinimum = brightnessMinimum;
this.brightnessMaximum = brightnessMaximum; this.brightnessMaximum = brightnessMaximum;
this.highBrightnessMode = highBrightnessMode; this.highBrightnessMode = highBrightnessMode;
this.highBrightnessTransitionPoint = highBrightnessTransitionPoint;
} }
/** /**
@ -103,9 +118,11 @@ public final class BrightnessInfo implements Parcelable {
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeFloat(brightness); dest.writeFloat(brightness);
dest.writeFloat(adjustedBrightness);
dest.writeFloat(brightnessMinimum); dest.writeFloat(brightnessMinimum);
dest.writeFloat(brightnessMaximum); dest.writeFloat(brightnessMaximum);
dest.writeInt(highBrightnessMode); dest.writeInt(highBrightnessMode);
dest.writeFloat(highBrightnessTransitionPoint);
} }
public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR = public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR =
@ -123,9 +140,11 @@ public final class BrightnessInfo implements Parcelable {
private BrightnessInfo(Parcel source) { private BrightnessInfo(Parcel source) {
brightness = source.readFloat(); brightness = source.readFloat();
adjustedBrightness = source.readFloat();
brightnessMinimum = source.readFloat(); brightnessMinimum = source.readFloat();
brightnessMaximum = source.readFloat(); brightnessMaximum = source.readFloat();
highBrightnessMode = source.readInt(); highBrightnessMode = source.readInt();
highBrightnessTransitionPoint = source.readFloat();
} }
} }

View File

@ -1257,6 +1257,23 @@ public final class DisplayManager {
*/ */
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS = String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
"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 * Key for default peak refresh rate
* *

View File

@ -361,6 +361,11 @@ public final class DisplayManagerGlobal {
for (int i = 0; i < numListeners; i++) { for (int i = 0; i < numListeners; i++) {
mask |= mDisplayListeners.get(i).mEventsMask; 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; return mask;
} }
@ -1047,12 +1052,17 @@ public final class DisplayManagerGlobal {
private static native void nSignalNativeCallbacks(float refreshRate); private static native void nSignalNativeCallbacks(float refreshRate);
// Called from AChoreographer via JNI. /**
// Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. * Called from AChoreographer via JNI.
private void registerNativeChoreographerForRefreshRateCallbacks() { * 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) { synchronized (mLock) {
registerCallbackIfNeededLocked();
mDispatchNativeCallbacks = true; mDispatchNativeCallbacks = true;
registerCallbackIfNeededLocked();
updateCallbackIfNeededLocked();
DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
if (display != null) { if (display != null) {
// We need to tell AChoreographer instances the current refresh rate so that apps // 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. * Called from AChoreographer via JNI.
private void unregisterNativeChoreographerForRefreshRateCallbacks() { * Unregisters AChoreographer from receiving refresh rate callbacks.
* Public for unit testing to be able to call this method.
*/
@VisibleForTesting
public void unregisterNativeChoreographerForRefreshRateCallbacks() {
synchronized (mLock) { synchronized (mLock) {
mDispatchNativeCallbacks = false; mDispatchNativeCallbacks = false;
updateCallbackIfNeededLocked();
} }
} }
} }

View File

@ -58,7 +58,7 @@ import java.util.List;
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants { public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
private static final String TAG = "FaceManager"; 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_ENROLL_RESULT = 100;
private static final int MSG_ACQUIRED = 101; private static final int MSG_ACQUIRED = 101;
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; 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"); throw new IllegalArgumentException("Must supply an authentication callback");
} }
if (cancel != null) { if (cancel != null && cancel.isCanceled()) {
if (cancel.isCanceled()) { Slog.w(TAG, "authentication already canceled");
Slog.w(TAG, "authentication already canceled"); return;
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
}
} }
if (mService != null) { if (mService != null) {
@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mCryptoObject = crypto; mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0; final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate"); Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, operationId, userId, mServiceReceiver, final long authId = mService.authenticate(mToken, operationId, userId,
mContext.getOpPackageName(), isKeyguardBypassEnabled); mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", 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
// Though this may not be a hardware issue, it will cause apps to give up or // try again later.
// try again later. callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
0 /* vendorCode */));
}
} finally { } finally {
Trace.endSection(); Trace.endSection();
} }
@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (cancel.isCanceled()) { if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled"); Slog.w(TAG, "Detection already cancelled");
return; return;
} else {
cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
} }
mFaceDetectionCallback = callback; mFaceDetectionCallback = callback;
try { 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) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", 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) { if (mService != null) {
try { try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName()); mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
} }
private void cancelFaceDetect() { private void cancelFaceDetect(long requestId) {
if (mService == null) { if (mService == null) {
return; return;
} }
try { try {
mService.cancelFaceDetect(mToken, mContext.getOpPackageName()); mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); 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 // 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 // It should not happen for anything other than FACE_ERROR_VENDOR, but
// warn and use the default if all else fails. // warn and use the default if all else fails.
// TODO(b/196639965): update string
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); 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 class OnAuthenticationCancelListener implements OnCancelListener {
private final CryptoObject mCrypto; private final long mAuthRequestId;
OnAuthenticationCancelListener(CryptoObject crypto) { OnAuthenticationCancelListener(long id) {
mCrypto = crypto; mAuthRequestId = id;
} }
@Override @Override
public void onCancel() { public void onCancel() {
cancelAuthentication(mCrypto); Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId);
cancelAuthentication(mAuthRequestId);
} }
} }
private class OnFaceDetectionCancelListener implements OnCancelListener { private class OnFaceDetectionCancelListener implements OnCancelListener {
private final long mAuthRequestId;
OnFaceDetectionCancelListener(long id) {
mAuthRequestId = id;
}
@Override @Override
public void onCancel() { public void onCancel() {
cancelFaceDetect(); Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId);
cancelFaceDetect(mAuthRequestId);
} }
} }

View File

@ -44,34 +44,36 @@ interface IFaceService {
// Retrieve static sensor properties for the specified sensor // Retrieve static sensor properties for the specified sensor
FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
// Authenticate the given sessionId with a face // Authenticate with a face. A requestId is returned that can be used to cancel this operation.
void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
String opPackageName, boolean isKeyguardBypassEnabled); String opPackageName, boolean isKeyguardBypassEnabled);
// Uses the face hardware to detect for the presence of a face, without giving details // Uses the face hardware to detect for the presence of a face, without giving details
// about accept/reject/lockout. // about accept/reject/lockout. A requestId is returned that can be used to cancel this
void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); // 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 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 // 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 // called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use // by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient(). // startPreparedClient().
void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
int cookie, boolean allowBackgroundAuthentication); String opPackageName, long requestId, int cookie,
boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client. // Starts authentication with the previously prepared client.
void startPreparedClient(int sensorId, int cookie); void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Cancel face detection // Cancel face detection for the given requestId.
void cancelFaceDetect(IBinder token, String opPackageName); void cancelFaceDetect(IBinder token, String opPackageName, long requestId);
// Same as above, with extra arguments. // 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 // Start face enrollment
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,

View File

@ -146,6 +146,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private CryptoObject mCryptoObject; private CryptoObject mCryptoObject;
@Nullable private RemoveTracker mRemoveTracker; @Nullable private RemoveTracker mRemoveTracker;
private Handler mHandler; private Handler mHandler;
@Nullable private float[] mEnrollStageThresholds;
/** /**
* Retrieves a list of properties for all fingerprint sensors on the device. * 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 class OnAuthenticationCancelListener implements OnCancelListener {
private android.hardware.biometrics.CryptoObject mCrypto; private final long mAuthRequestId;
public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { OnAuthenticationCancelListener(long id) {
mCrypto = crypto; mAuthRequestId = id;
} }
@Override @Override
public void onCancel() { public void onCancel() {
cancelAuthentication(mCrypto); Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
cancelAuthentication(mAuthRequestId);
} }
} }
private class OnFingerprintDetectionCancelListener implements OnCancelListener { private class OnFingerprintDetectionCancelListener implements OnCancelListener {
private final long mAuthRequestId;
OnFingerprintDetectionCancelListener(long id) {
mAuthRequestId = id;
}
@Override @Override
public void onCancel() { 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"); throw new IllegalArgumentException("Must supply an authentication callback");
} }
if (cancel != null) { if (cancel != null && cancel.isCanceled()) {
if (cancel.isCanceled()) { Slog.w(TAG, "authentication already canceled");
Slog.w(TAG, "authentication already canceled"); return;
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
}
} }
if (mService != null) { if (mService != null) {
@ -567,8 +572,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mAuthenticationCallback = callback; mAuthenticationCallback = callback;
mCryptoObject = crypto; mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0; final long operationId = crypto != null ? crypto.getOpId() : 0;
mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver, final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
mContext.getOpPackageName()); mServiceReceiver, mContext.getOpPackageName());
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", 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 // 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()) { if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled"); Slog.w(TAG, "Detection already cancelled");
return; return;
} else {
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
} }
mFingerprintDetectionCallback = callback; mFingerprintDetectionCallback = callback;
try { try {
mService.detectFingerprint(mToken, userId, mServiceReceiver, final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
mContext.getOpPackageName()); mContext.getOpPackageName());
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e); Slog.w(TAG, "Remote exception when requesting finger detect", e);
} }
@ -843,26 +850,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return hasEnrolledFingerprints(userId); 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<FingerprintSensorPropertiesInternal> 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 * @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 { if (mService != null) try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName()); mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
private void cancelFingerprintDetect() { private void cancelFingerprintDetect(long requestId) {
if (mService == null) { if (mService == null) {
return; return;
} }
try { try {
mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName()); mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); 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 * @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 // 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 // It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but
// warn and use the default if all else fails. // warn and use the default if all else fails.
// TODO(b/196639965): update string
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
return ""; return context.getString(
com.android.internal.R.string.fingerprint_error_vendor_unknown);
} }
/** /**

View File

@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener
* Defines behavior in response to state update * Defines behavior in response to state update
* @param newState new state of fingerprint sensor * @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) {};
} }

View File

@ -48,15 +48,16 @@ interface IFingerprintService {
// Retrieve static sensor properties for the specified sensor // Retrieve static sensor properties for the specified sensor
FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
// Authenticate the given sessionId with a fingerprint. This is protected by // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC
// USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes // permission. This is effectively deprecated, since it only comes through FingerprintManager
// through FingerprintManager now. // now. A requestId is returned that can be used to cancel this operation.
void authenticate(IBinder token, long operationId, int sensorId, int userId, long authenticate(IBinder token, long operationId, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName); IFingerprintServiceReceiver receiver, String opPackageName);
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details // Uses the fingerprint hardware to detect for the presence of a finger, without giving details
// about accept/reject/lockout. // about accept/reject/lockout. A requestId is returned that can be used to cancel this
void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, // operation.
long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
String opPackageName); String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication. // 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 // by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient(). // startPreparedClient().
void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
boolean allowBackgroundAuthentication); int cookie, boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client. // Starts authentication with the previously prepared client.
void startPreparedClient(int sensorId, int cookie); void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Cancel finger detection // Cancel finger detection for the given requestId.
void cancelFingerprintDetect(IBinder token, String opPackageName); void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId);
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
// an additional uid, pid, userid. // 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 // Start fingerprint enrollment
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, 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. // Determine if a user has at least one enrolled fingerprint.
boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName); 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<FingerprintSensorPropertiesInternal> sensors, String opPackageName);
// Return the LockoutTracker status for the specified user // Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int sensorId, int userId); int getLockoutModeForUser(int sensorId, int userId);

View File

@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint;
*/ */
oneway interface IFingerprintStateListener { oneway interface IFingerprintStateListener {
void onStateChanged(int newState); void onStateChanged(int newState);
void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
} }

View File

@ -1749,12 +1749,12 @@ public class InputMethodService extends AbstractInputMethodService {
if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) { if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
return false; return false;
} }
if ((mInputEditorInfo != null if (mInputEditorInfo != null
&& (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) && ((mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0
// If app window has portrait orientation, regardless of what display orientation // If app window has portrait orientation, regardless of what display orientation
// is, IME shouldn't use fullscreen-mode. // is, IME shouldn't use fullscreen-mode.
|| (mInputEditorInfo.internalImeOptions || (mInputEditorInfo.internalImeOptions
& EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) { & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0)) {
return false; return false;
} }
return true; return true;

View File

@ -270,6 +270,16 @@ public final class BatteryUsageStats implements Parcelable {
return mUserBatteryConsumers; 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. * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
*/ */

View File

@ -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_SIZE = 1 << LOG_MAIN_INDEX_SIZE;
private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1; private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1;
// Debuggable builds will throw an AssertionError if the number of map entries exceeds: // 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. * We next warn when we exceed this bucket size.

View File

@ -17,6 +17,7 @@
package android.os; package android.os;
import android.app.Activity; import android.app.Activity;
import android.app.GameManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
@ -26,8 +27,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@ -37,9 +36,6 @@ import dalvik.system.VMRuntime;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; 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_ALLOWLIST_ALL = "*";
private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt"; 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 = "android.app.action.ANGLE_FOR_ANDROID";
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE = private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
"android.app.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 ClassLoader mClassLoader;
private String mLibrarySearchPaths; private String mLibrarySearchPaths;
private String mLibraryPermittedPaths; private String mLibraryPermittedPaths;
private GameManager mGameManager;
private int mAngleOptInIndex = -1; private int mAngleOptInIndex = -1;
@ -133,6 +127,8 @@ public class GraphicsEnvironment {
final ApplicationInfo appInfoWithMetaData = final ApplicationInfo appInfoWithMetaData =
getAppInfoWithMetadata(context, pm, packageName); getAppInfoWithMetadata(context, pm, packageName);
mGameManager = context.getSystemService(GameManager.class);
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers"); Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData); setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@ -150,6 +146,23 @@ public class GraphicsEnvironment {
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); 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 * Query to determine if ANGLE should be used
*/ */
@ -164,21 +177,16 @@ public class GraphicsEnvironment {
Log.v(TAG, "ANGLE Developer option for '" + packageName + "' " Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
+ "set to: '" + devOptIn + "'"); + "set to: '" + devOptIn + "'");
// We only want to use ANGLE if the app is in the allowlist, or the developer has // We only want to use ANGLE if the developer has explicitly chosen something other than
// explicitly chosen something other than default driver. // 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);
final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE); final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
if (allowed) {
Log.v(TAG, "ANGLE allowlist includes " + packageName);
}
if (requested) { if (requested) {
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn); 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) { private int getVulkanVersion(PackageManager pm) {
@ -474,117 +482,6 @@ public class GraphicsEnvironment {
return debugPackage; 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<String> 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 * 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 (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 setAngleInfo() with the package name and the developer option value
// we need to call setupAngleRulesApk() with the package name and the developer //(native/angle/other). Then later when we are actually trying to load a driver,
// option value (native/angle/other). Then later when we are actually trying to //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
// load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before //answer yes/no based on the previously set developer option value.
// and can confidently answer yes/no based on the previously set developer final String devOptIn;
// option value. final String[] features = getAngleEglFeatures(context, bundle);
final String devOptIn = getDriverForPackage(context, bundle, packageName); final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
if (gameModeEnabledAngle) {
if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) { devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
// We setup ANGLE with a temp rules file, so we're done here. } else {
return true; devOptIn = getDriverForPackage(context, bundle, packageName);
} }
setAngleInfo(paths, packageName, devOptIn, features);
String[] features = getAngleEglFeatures(context, bundle); return true;
if (setupAngleRulesApk(
anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
// ANGLE with rules is set up from the APK, hence return.
return true;
}
return false;
} }
/** /**
@ -956,7 +846,7 @@ public class GraphicsEnvironment {
private static native void setGpuStats(String driverPackageName, String driverVersionName, private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion); long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
private static native void setAngleInfo(String path, String appPackage, String devOptIn, 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 getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable(); private static native boolean setInjectLayersPrSetDumpable();

View File

@ -1,6 +1,5 @@
# Bug component: 554432 # Bug component: 554432
alexbuy@google.com alexbuy@google.com
schfan@google.com schfan@google.com
toddke@google.com
zyy@google.com zyy@google.com
patb@google.com patb@google.com

View File

@ -18,6 +18,7 @@ package android.os.storage;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.IVold; import android.os.IVold;
import java.util.List; import java.util.List;
@ -135,4 +136,19 @@ public abstract class StorageManagerInternal {
* {@link VolumeInfo#isPrimary()} * {@link VolumeInfo#isPrimary()}
*/ */
public abstract List<String> getPrimaryVolumeIds(); public abstract List<String> 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);
} }

View File

@ -2241,6 +2241,21 @@ public final class Settings {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS"; public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS";
/**
* Activity Action: Show screen that lets user configure wifi tethering.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard against this.
* <p>
* Input: Nothing
* <p>
* 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. * 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}. * Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}.
@ -11844,6 +11859,12 @@ public final class Settings {
@Readable @Readable
public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed"; 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. * 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 = public static final String ANGLE_GL_DRIVER_SELECTION_VALUES =
"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. * Lists of ANGLE EGL features for debugging.
* Each list of features is separated by a comma, each feature in each list is separated by * 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 = public static final String POWER_BUTTON_LONG_PRESS =
"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. * Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
* Allowable values detailed in frameworks/base/core/res/res/values/config.xml. * Allowable values detailed in frameworks/base/core/res/res/values/config.xml.

View File

@ -436,7 +436,7 @@ public class StatusBarNotification implements Parcelable {
try { try {
ApplicationInfo ai = context.getPackageManager() ApplicationInfo ai = context.getPackageManager()
.getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
getUserId()); getNormalizedUserId());
mContext = context.createApplicationContext(ai, mContext = context.createApplicationContext(ai,
Context.CONTEXT_RESTRICTED); Context.CONTEXT_RESTRICTED);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {

View File

@ -24,7 +24,7 @@ import com.android.internal.os.IResultReceiver;
/** /**
* System-wide on-device translation service. * System-wide on-device translation service.
* *
* <p>Services requests to translate text between different languages. The primary use case for this * <p>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 * service is automatic translation of text and web views, when the auto Translate feature is
* enabled. * enabled.
* *

View File

@ -48,6 +48,7 @@ import android.view.translation.TranslationManager;
import android.view.translation.TranslationRequest; import android.view.translation.TranslationRequest;
import android.view.translation.TranslationResponse; import android.view.translation.TranslationResponse;
import android.view.translation.TranslationSpec; import android.view.translation.TranslationSpec;
import android.view.translation.Translator;
import com.android.internal.os.IResultReceiver; import com.android.internal.os.IResultReceiver;
@ -81,7 +82,10 @@ public abstract class TranslationService extends Service {
* android.R.styleable#TranslationService translation-service}&gt;</code> tag. * android.R.styleable#TranslationService translation-service}&gt;</code> tag.
* *
* <p>Here's an example of how to use it on {@code AndroidManifest.xml}: * <p>Here's an example of how to use it on {@code AndroidManifest.xml}:
* TODO: fill in doc example (check CCService/AFService). * <pre> &lt;translation-service
* android:settingsActivity="foo.bar.SettingsActivity"
* . . .
* /&gt;</pre>
*/ */
public static final String SERVICE_META_DATA = "android.translation_service"; 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); void onTranslationSuccess(@NonNull TranslationResponse response);
/** /**
* TODO: implement javadoc
* @removed use {@link #onTranslationSuccess} with an error response instead. * @removed use {@link #onTranslationSuccess} with an error response instead.
*/ */
@Deprecated @Deprecated
@ -225,7 +228,7 @@ public abstract class TranslationService extends Service {
* should call back with {@code false}.</p> * should call back with {@code false}.</p>
* *
* @param translationContext the {@link TranslationContext} of the session being created. * @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. * @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 // 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<Boolean> callback); int sessionId, @NonNull Consumer<Boolean> callback);
/** /**
* TODO: fill in javadoc.
*
* @removed use {@link #onCreateTranslationSession(TranslationContext, int, Consumer)} * @removed use {@link #onCreateTranslationSession(TranslationContext, int, Consumer)}
* instead. * instead.
*/ */
@ -246,19 +247,16 @@ public abstract class TranslationService extends Service {
} }
/** /**
* TODO: fill in javadoc. * Called when a translation session is finished.
* *
* @param sessionId * <p>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); public abstract void onFinishTranslationSession(int sessionId);
/** /**
* TODO: fill in javadoc.
*
* @param request
* @param sessionId
* @param callback
* @param cancellationSignal
* @removed use * @removed use
* {@link #onTranslationRequest(TranslationRequest, int, CancellationSignal, Consumer)} instead. * {@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 * {@link TranslationRequest#FLAG_PARTIAL_RESPONSES} was set, the service may call
* {@code callback.accept()} multiple times with partial responses.</p> * {@code callback.accept()} multiple times with partial responses.</p>
* *
* @param request * @param request The translation request containing the data to be translated.
* @param sessionId * @param sessionId id of the session that sent the translation request.
* @param callback * @param cancellationSignal A {@link CancellationSignal} that notifies when a client has
* @param cancellationSignal * cancelled the operation in progress.
* @param callback {@link Consumer} to pass back the translation response.
*/ */
public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId, public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
@Nullable CancellationSignal cancellationSignal, @Nullable CancellationSignal cancellationSignal,
@NonNull Consumer<TranslationResponse> callback); @NonNull Consumer<TranslationResponse> callback);
/** /**
* TODO: fill in javadoc * Called to request a set of {@link TranslationCapability}s that are supported by the service.
*
* <p>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.</p>
* *
* <p>Must call {@code callback.accept} to pass back the set of translation capabilities.</p> * <p>Must call {@code callback.accept} to pass back the set of translation capabilities.</p>
* *
* @param sourceFormat * @param sourceFormat data format restriction of the translation source spec.
* @param targetFormat * @param targetFormat data format restriction of the translation target spec.
* @param callback * @param callback {@link Consumer} to pass back the set of translation capabilities.
*/ */
public abstract void onTranslationCapabilitiesRequest( public abstract void onTranslationCapabilitiesRequest(
@TranslationSpec.DataFormat int sourceFormat, @TranslationSpec.DataFormat int sourceFormat,

View File

@ -96,6 +96,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier; 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_REQUEST_WALLPAPER_COLORS = 10050;
private static final int MSG_ZOOM = 10100; private static final int MSG_ZOOM = 10100;
private static final int MSG_SCALE_PREVIEW = 10110; private static final int MSG_SCALE_PREVIEW = 10110;
private static final int MSG_REPORT_SHOWN = 10150;
private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY, private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
Float.NEGATIVE_INFINITY); Float.NEGATIVE_INFINITY);
@ -526,6 +528,39 @@ public abstract class WallpaperService extends Service {
return false; 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 * Control whether this wallpaper will receive raw touch events
* from the window manager as the user interacts with the window * 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) { void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
if (mDestroyed) { if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface: destroyed"); Log.w(TAG, "Ignoring updateSurface due to destroyed");
} }
boolean fixedSize = false; boolean fixedSize = false;
@ -1197,7 +1232,6 @@ public abstract class WallpaperService extends Service {
+ this); + this);
onVisibilityChanged(false); onVisibilityChanged(false);
} }
} finally { } finally {
mIsCreating = false; mIsCreating = false;
mSurfaceCreated = true; mSurfaceCreated = true;
@ -1207,7 +1241,7 @@ public abstract class WallpaperService extends Service {
processLocalColors(mPendingXOffset, mPendingXOffsetStep); processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} }
reposition(); reposition();
mIWallpaperEngine.reportShown(); reportEngineShown(shouldWaitForEngineShown());
} }
} catch (RemoteException ex) { } catch (RemoteException ex) {
} }
@ -2048,6 +2082,8 @@ public abstract class WallpaperService extends Service {
mShownReported = true; mShownReported = true;
try { try {
mConnection.engineShown(this); mConnection.engineShown(this);
Log.d(TAG, "Wallpaper has updated the surface:"
+ mWallpaperManager.getWallpaperInfo());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "Wallpaper host disappeared", e); Log.w(TAG, "Wallpaper host disappeared", e);
return; return;
@ -2201,6 +2237,9 @@ public abstract class WallpaperService extends Service {
// Connection went away, nothing to do in here. // Connection went away, nothing to do in here.
} }
} break; } break;
case MSG_REPORT_SHOWN: {
reportShown();
} break;
default : default :
Log.w(TAG, "Unknown message type " + message.what); Log.w(TAG, "Unknown message type " + message.what);
} }

View File

@ -115,7 +115,7 @@ public abstract class RecognitionService extends Service {
@NonNull AttributionSource attributionSource) { @NonNull AttributionSource attributionSource) {
try { try {
if (mCurrentCallback == null) { if (mCurrentCallback == null) {
boolean preflightPermissionCheckPassed = checkPermissionForPreflight( boolean preflightPermissionCheckPassed = checkPermissionForPreflightNotHardDenied(
attributionSource); attributionSource);
if (preflightPermissionCheckPassed) { if (preflightPermissionCheckPassed) {
if (DBG) { if (DBG) {
@ -470,10 +470,11 @@ public abstract class RecognitionService extends Service {
return mStartedDataDelivery; return mStartedDataDelivery;
} }
private boolean checkPermissionForPreflight(AttributionSource attributionSource) { private boolean checkPermissionForPreflightNotHardDenied(AttributionSource attributionSource) {
return PermissionChecker.checkPermissionForPreflight(RecognitionService.this, int result = PermissionChecker.checkPermissionForPreflight(RecognitionService.this,
Manifest.permission.RECORD_AUDIO, attributionSource) Manifest.permission.RECORD_AUDIO, attributionSource);
== PermissionChecker.PERMISSION_GRANTED; return result == PermissionChecker.PERMISSION_GRANTED
|| result == PermissionChecker.PERMISSION_SOFT_DENIED;
} }
void finishDataDelivery() { void finishDataDelivery() {

View File

@ -782,7 +782,7 @@ public class TextLine {
int spanStart = runStart; int spanStart = runStart;
int spanLimit; int spanLimit;
if (mSpanned == null) { if (mSpanned == null || runStart == runLimit) {
spanLimit = runLimit; spanLimit = runLimit;
} else { } else {
int target = after ? offset + 1 : offset; int target = after ? offset + 1 : offset;

View File

@ -62,6 +62,13 @@ public class TranslationTransformationMethod implements TransformationMethod2 {
return mOriginalTranslationMethod; return mOriginalTranslationMethod;
} }
/**
* Returns the {@link TextView}'s {@link ViewTranslationResponse}.
*/
public ViewTranslationResponse getViewTranslationResponse() {
return mTranslationResponse;
}
@Override @Override
public CharSequence getTransformation(CharSequence source, View view) { public CharSequence getTransformation(CharSequence source, View view) {
if (!mAllowLengthChanges) { if (!mAllowLengthChanges) {

View File

@ -814,9 +814,10 @@ interface IWindowManager
* @param displayId The display associated with the window context * @param displayId The display associated with the window context
* @param options A bundle used to pass window-related options and choose the right DisplayArea * @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); in Bundle options);
/** /**

View File

@ -53,6 +53,10 @@ public class ScrollCaptureResponse implements Parcelable {
@Nullable @Nullable
private String mWindowTitle = null; private String mWindowTitle = null;
/** The package which owns the window. */
@Nullable
private String mPackageName = null;
/** Carries additional logging and debugging information when enabled. */ /** Carries additional logging and debugging information when enabled. */
@NonNull @NonNull
@DataClass.PluralOf("message") @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! // DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code // CHECKSTYLE:OFF Generated code
@ -97,6 +101,7 @@ public class ScrollCaptureResponse implements Parcelable {
@Nullable Rect windowBounds, @Nullable Rect windowBounds,
@Nullable Rect boundsInWindow, @Nullable Rect boundsInWindow,
@Nullable String windowTitle, @Nullable String windowTitle,
@Nullable String packageName,
@NonNull ArrayList<String> messages) { @NonNull ArrayList<String> messages) {
this.mDescription = description; this.mDescription = description;
com.android.internal.util.AnnotationValidations.validate( com.android.internal.util.AnnotationValidations.validate(
@ -105,6 +110,7 @@ public class ScrollCaptureResponse implements Parcelable {
this.mWindowBounds = windowBounds; this.mWindowBounds = windowBounds;
this.mBoundsInWindow = boundsInWindow; this.mBoundsInWindow = boundsInWindow;
this.mWindowTitle = windowTitle; this.mWindowTitle = windowTitle;
this.mPackageName = packageName;
this.mMessages = messages; this.mMessages = messages;
com.android.internal.util.AnnotationValidations.validate( com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMessages); NonNull.class, null, mMessages);
@ -152,6 +158,14 @@ public class ScrollCaptureResponse implements Parcelable {
return mWindowTitle; 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. * Carries additional logging and debugging information when enabled.
*/ */
@ -172,6 +186,7 @@ public class ScrollCaptureResponse implements Parcelable {
"windowBounds = " + mWindowBounds + ", " + "windowBounds = " + mWindowBounds + ", " +
"boundsInWindow = " + mBoundsInWindow + ", " + "boundsInWindow = " + mBoundsInWindow + ", " +
"windowTitle = " + mWindowTitle + ", " + "windowTitle = " + mWindowTitle + ", " +
"packageName = " + mPackageName + ", " +
"messages = " + mMessages + "messages = " + mMessages +
" }"; " }";
} }
@ -187,12 +202,14 @@ public class ScrollCaptureResponse implements Parcelable {
if (mWindowBounds != null) flg |= 0x4; if (mWindowBounds != null) flg |= 0x4;
if (mBoundsInWindow != null) flg |= 0x8; if (mBoundsInWindow != null) flg |= 0x8;
if (mWindowTitle != null) flg |= 0x10; if (mWindowTitle != null) flg |= 0x10;
if (mPackageName != null) flg |= 0x20;
dest.writeByte(flg); dest.writeByte(flg);
dest.writeString(mDescription); dest.writeString(mDescription);
if (mConnection != null) dest.writeStrongInterface(mConnection); if (mConnection != null) dest.writeStrongInterface(mConnection);
if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags); if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags); if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
if (mWindowTitle != null) dest.writeString(mWindowTitle); if (mWindowTitle != null) dest.writeString(mWindowTitle);
if (mPackageName != null) dest.writeString(mPackageName);
dest.writeStringList(mMessages); dest.writeStringList(mMessages);
} }
@ -213,6 +230,7 @@ public class ScrollCaptureResponse implements Parcelable {
Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR); Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
Rect boundsInWindow = (flg & 0x8) == 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 windowTitle = (flg & 0x10) == 0 ? null : in.readString();
String packageName = (flg & 0x20) == 0 ? null : in.readString();
ArrayList<String> messages = new ArrayList<>(); ArrayList<String> messages = new ArrayList<>();
in.readStringList(messages); in.readStringList(messages);
@ -223,6 +241,7 @@ public class ScrollCaptureResponse implements Parcelable {
this.mWindowBounds = windowBounds; this.mWindowBounds = windowBounds;
this.mBoundsInWindow = boundsInWindow; this.mBoundsInWindow = boundsInWindow;
this.mWindowTitle = windowTitle; this.mWindowTitle = windowTitle;
this.mPackageName = packageName;
this.mMessages = messages; this.mMessages = messages;
com.android.internal.util.AnnotationValidations.validate( com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMessages); NonNull.class, null, mMessages);
@ -256,6 +275,7 @@ public class ScrollCaptureResponse implements Parcelable {
private @Nullable Rect mWindowBounds; private @Nullable Rect mWindowBounds;
private @Nullable Rect mBoundsInWindow; private @Nullable Rect mBoundsInWindow;
private @Nullable String mWindowTitle; private @Nullable String mWindowTitle;
private @Nullable String mPackageName;
private @NonNull ArrayList<String> mMessages; private @NonNull ArrayList<String> mMessages;
private long mBuilderFieldsSet = 0L; private long mBuilderFieldsSet = 0L;
@ -318,13 +338,24 @@ public class ScrollCaptureResponse implements Parcelable {
return this; 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. * Carries additional logging and debugging information when enabled.
*/ */
@DataClass.Generated.Member @DataClass.Generated.Member
public @NonNull Builder setMessages(@NonNull ArrayList<String> value) { public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
checkNotUsed(); checkNotUsed();
mBuilderFieldsSet |= 0x20; mBuilderFieldsSet |= 0x40;
mMessages = value; mMessages = value;
return this; return this;
} }
@ -340,7 +371,7 @@ public class ScrollCaptureResponse implements Parcelable {
/** Builds the instance. This builder should not be touched after calling this! */ /** Builds the instance. This builder should not be touched after calling this! */
public @NonNull ScrollCaptureResponse build() { public @NonNull ScrollCaptureResponse build() {
checkNotUsed(); checkNotUsed();
mBuilderFieldsSet |= 0x40; // Mark builder used mBuilderFieldsSet |= 0x80; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) { if ((mBuilderFieldsSet & 0x1) == 0) {
mDescription = ""; mDescription = "";
@ -358,6 +389,9 @@ public class ScrollCaptureResponse implements Parcelable {
mWindowTitle = null; mWindowTitle = null;
} }
if ((mBuilderFieldsSet & 0x20) == 0) { if ((mBuilderFieldsSet & 0x20) == 0) {
mPackageName = null;
}
if ((mBuilderFieldsSet & 0x40) == 0) {
mMessages = new ArrayList<>(); mMessages = new ArrayList<>();
} }
ScrollCaptureResponse o = new ScrollCaptureResponse( ScrollCaptureResponse o = new ScrollCaptureResponse(
@ -366,12 +400,13 @@ public class ScrollCaptureResponse implements Parcelable {
mWindowBounds, mWindowBounds,
mBoundsInWindow, mBoundsInWindow,
mWindowTitle, mWindowTitle,
mPackageName,
mMessages); mMessages);
return o; return o;
} }
private void checkNotUsed() { private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x40) != 0) { if ((mBuilderFieldsSet & 0x80) != 0) {
throw new IllegalStateException( throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead"); "This Builder should not be reused. Use a new Builder instance instead");
} }
@ -379,10 +414,10 @@ public class ScrollCaptureResponse implements Parcelable {
} }
@DataClass.Generated( @DataClass.Generated(
time = 1614833185795L, time = 1628630366187L,
codegenVersion = "1.0.22", codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java", 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<java.lang.String> 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<java.lang.String> 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 @Deprecated
private void __metadata() {} private void __metadata() {}

View File

@ -98,6 +98,7 @@ public class Surface implements Parcelable {
private static native int nativeSetFrameRate( private static native int nativeSetFrameRate(
long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy); long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
private static native void nativeDestroy(long nativeObject);
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR = public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() { new Parcelable.Creator<Surface>() {
@ -339,6 +340,9 @@ public class Surface implements Parcelable {
*/ */
@UnsupportedAppUsage @UnsupportedAppUsage
public void destroy() { public void destroy() {
if (mNativeObject != 0) {
nativeDestroy(mNativeObject);
}
release(); release();
} }

View File

@ -903,7 +903,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mSurfaceAlpha = 1f; mSurfaceAlpha = 1f;
synchronized (mSurfaceControlLock) { synchronized (mSurfaceControlLock) {
mSurface.release(); mSurface.destroy();
if (mBlastBufferQueue != null) { if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy(); mBlastBufferQueue.destroy();
mBlastBufferQueue = null; mBlastBufferQueue = null;

View File

@ -20830,13 +20830,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;
} }
notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
mAttachInfo = null; mAttachInfo = null;
if (mOverlay != null) { if (mOverlay != null) {
mOverlay.getOverlayView().dispatchDetachedFromWindow(); mOverlay.getOverlayView().dispatchDetachedFromWindow();
} }
notifyEnterOrExitForAutoFillIfNeeded(false); notifyEnterOrExitForAutoFillIfNeeded(false);
notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
} }
/** /**

View File

@ -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()) { if (mSurfaceControl.isValid()) {
updateOpacity(mWindowAttributes, dragResizing); updateOpacity(mWindowAttributes, dragResizing,
surfaceControlChanged /*forceUpdate */);
} }
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() 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 // RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
// SurfaceControl. // SurfaceControl.
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId() surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
|| (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) || surfaceControlChanged) && mSurface.isValid();
== RELAYOUT_RES_SURFACE_CHANGED)
&& mSurface.isValid();
if (surfaceReplaced) { if (surfaceReplaced) {
mSurfaceSequenceId++; mSurfaceSequenceId++;
} }
@ -7824,7 +7827,8 @@ public final class ViewRootImpl implements ViewParent,
return relayoutResult; return relayoutResult;
} }
private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing) { private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
boolean forceUpdate) {
boolean opaque = false; boolean opaque = false;
if (!PixelFormat.formatHasAlpha(params.format) if (!PixelFormat.formatHasAlpha(params.format)
@ -7840,7 +7844,7 @@ public final class ViewRootImpl implements ViewParent,
opaque = true; opaque = true;
} }
if (mIsSurfaceOpaque == opaque) { if (!forceUpdate && mIsSurfaceOpaque == opaque) {
return; return;
} }
@ -9493,6 +9497,7 @@ public final class ViewRootImpl implements ViewParent,
ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder(); ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
response.setWindowTitle(getTitle().toString()); response.setWindowTitle(getTitle().toString());
response.setPackageName(mContext.getPackageName());
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IndentingPrintWriter pw = new IndentingPrintWriter(writer); IndentingPrintWriter pw = new IndentingPrintWriter(writer);

View File

@ -57,6 +57,9 @@ public class TranslateAnimation extends Animation {
/** @hide */ /** @hide */
protected float mToYDelta; protected float mToYDelta;
private int mWidth;
private int mParentWidth;
/** /**
* Constructor used when a TranslateAnimation is loaded from a resource. * 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); mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight); mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
mToYDelta = resolveSize(mToYType, mToYValue, 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;
} }
} }

View File

@ -40,15 +40,18 @@ import java.util.function.Consumer;
public final class TranslationCapability implements Parcelable { 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; 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; 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; public static final @ModelState int STATE_ON_DEVICE = 3;
/** /**
@ -305,7 +308,7 @@ public final class TranslationCapability implements Parcelable {
}; };
@DataClass.Generated( @DataClass.Generated(
time = 1624307114468L, time = 1629158466039L,
codegenVersion = "1.0.23", codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationCapability.java", 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)") 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)")

View File

@ -39,12 +39,16 @@ public final class TranslationRequest implements Parcelable {
public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1; public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1;
/** /**
* Indicates this request wants to receive the dictionary result. * Indicates this request wants to receive the dictionary result.
* TODO: describe the structure of the result. *
* <p>See {@link TranslationResponseValue#EXTRA_DEFINITIONS} for more detail on the structure
* of the returned data.
*/ */
public static final @RequestFlags int FLAG_DICTIONARY_RESULT = 0x2; public static final @RequestFlags int FLAG_DICTIONARY_RESULT = 0x2;
/** /**
* Indicates this request wants to receive the transliteration result. * Indicates this request wants to receive the transliteration result.
* TODO: describe the structure of the result. *
* <p>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; public static final @RequestFlags int FLAG_TRANSLITERATION_RESULT = 0x4;
/** /**
@ -327,7 +331,8 @@ public final class TranslationRequest implements Parcelable {
return this; return this;
} }
/** @see #setTranslationRequestValues /**
* @see #setTranslationRequestValues
* @removed * @removed
*/ */
@DataClass.Generated.Member @DataClass.Generated.Member
@ -352,7 +357,8 @@ public final class TranslationRequest implements Parcelable {
return this; return this;
} }
/** @see #setViewTranslationRequests /**
* @see #setViewTranslationRequests
* @removed * @removed
*/ */
@DataClass.Generated.Member @DataClass.Generated.Member
@ -394,7 +400,7 @@ public final class TranslationRequest implements Parcelable {
} }
@DataClass.Generated( @DataClass.Generated(
time = 1620429997487L, time = 1629159107226L,
codegenVersion = "1.0.23", codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java", 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<android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"viewTranslationRequest\") java.util.List<android.view.translation.ViewTranslationRequest> mViewTranslationRequests\nprivate static int defaultFlags()\nprivate static java.util.List<android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nprivate static java.util.List<android.view.translation.ViewTranslationRequest> 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 []") 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<android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"viewTranslationRequest\") java.util.List<android.view.translation.ViewTranslationRequest> mViewTranslationRequests\nprivate static int defaultFlags()\nprivate static java.util.List<android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nprivate static java.util.List<android.view.translation.ViewTranslationRequest> 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 []")

View File

@ -93,9 +93,11 @@ public final class TranslationResponseValue implements Parcelable {
@NonNull @NonNull
private final Bundle mExtras; private final Bundle mExtras;
// TODO: Add example of transliteration.
/** /**
* The transliteration result of the translated text. * The transliteration result of the translated text.
* TODO: Describe the result structure. *
* <p>This returns a CharSequence representation of the transliteration of the translated text.
*/ */
@Nullable @Nullable
private final CharSequence mTransliteration; private final CharSequence mTransliteration;
@ -223,7 +225,8 @@ public final class TranslationResponseValue implements Parcelable {
/** /**
* The transliteration result of the translated text. * The transliteration result of the translated text.
* TODO: Describe the result structure. *
* <p>This returns a CharSequence representation of the transliteration of the translated text.
*/ */
@DataClass.Generated.Member @DataClass.Generated.Member
public @Nullable CharSequence getTransliteration() { public @Nullable CharSequence getTransliteration() {
@ -407,7 +410,8 @@ public final class TranslationResponseValue implements Parcelable {
/** /**
* The transliteration result of the translated text. * The transliteration result of the translated text.
* TODO: Describe the result structure. *
* <p>This returns a CharSequence representation of the transliteration of the translated text.
*/ */
@DataClass.Generated.Member @DataClass.Generated.Member
public @NonNull Builder setTransliteration(@NonNull CharSequence value) { public @NonNull Builder setTransliteration(@NonNull CharSequence value) {
@ -448,7 +452,7 @@ public final class TranslationResponseValue implements Parcelable {
} }
@DataClass.Generated( @DataClass.Generated(
time = 1622133051937L, time = 1631057245846L,
codegenVersion = "1.0.23", codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java", 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 []") 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 []")

View File

@ -356,7 +356,11 @@ public class UiTranslationController {
} }
for (int i = 0; i < translatedResult.size(); i++) { for (int i = 0; i < translatedResult.size(); i++) {
final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i)); final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i));
final View view = mViews.get(autofillId).get(); final WeakReference<View> viewRef = mViews.get(autofillId);
if (viewRef == null) {
continue;
}
final View view = viewRef.get();
if (view == null) { if (view == null) {
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
+ " may be gone."); + " may be gone.");
@ -416,22 +420,30 @@ public class UiTranslationController {
Log.w(TAG, "No AutofillId is set in ViewTranslationResponse"); Log.w(TAG, "No AutofillId is set in ViewTranslationResponse");
continue; continue;
} }
final View view = mViews.get(autofillId).get(); final WeakReference<View> viewRef = mViews.get(autofillId);
if (viewRef == null) {
continue;
}
final View view = viewRef.get();
if (view == null) { if (view == null) {
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
+ " may be gone."); + " may be gone.");
continue; continue;
} }
mActivity.runOnUiThread(() -> { mActivity.runOnUiThread(() -> {
ViewTranslationCallback callback = view.getViewTranslationCallback();
if (view.getViewTranslationResponse() != null if (view.getViewTranslationResponse() != null
&& view.getViewTranslationResponse().equals(response)) { && view.getViewTranslationResponse().equals(response)) {
if (DEBUG) { if (callback instanceof TextViewTranslationCallback) {
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId if (((TextViewTranslationCallback) callback).isShowingTranslation()) {
+ ". Ignoring."); if (DEBUG) {
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
+ ". Ignoring.");
}
return;
}
} }
return;
} }
ViewTranslationCallback callback = view.getViewTranslationCallback();
if (callback == null) { if (callback == null) {
if (view instanceof TextView) { if (view instanceof TextView) {
// developer doesn't provide their override, we set the default 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(); final View rootView = roots.get(rootNum).getView();
if (rootView instanceof ViewGroup) { if (rootView instanceof ViewGroup) {
findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds); findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds);
} else {
addViewIfNeeded(sourceViewIds, rootView);
} }
addViewIfNeeded(sourceViewIds, rootView);
} }
} }
@ -603,9 +614,8 @@ public class UiTranslationController {
final View child = viewGroup.getChildAt(i); final View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup) { if (child instanceof ViewGroup) {
findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds); findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds);
} else {
addViewIfNeeded(sourceViewIds, child);
} }
addViewIfNeeded(sourceViewIds, child);
} }
} }

View File

@ -33,6 +33,7 @@ import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.autofill.AutofillId; import android.view.autofill.AutofillId;
import android.widget.TextView;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
@ -42,11 +43,50 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor; 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 * <p>The {@link UiTranslationManager} class provides ways for apps to use the ui translation
* function in framework. * function in framework.
*
* <p> 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:
*
* <pre><code>
* 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<ViewTranslationRequest> 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);
* }
* }
* </code></pre>
*
* <p>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 { 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 * 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. * is available to the owning application itself and also the current input method.
* <p> * <p>
* The application whose UI is being translated can use this to customize the UI Translation * 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 * behavior in ways that aren't made easy by methods like
* View#onCreateTranslationRequest(). * {@link View#onCreateViewTranslationRequest(int[], Consumer)}.
*
* <p> * <p>
* Input methods can use this to offer complementary features to UI Translation; for example, * 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 * enabling outgoing message translation when the system is translating incoming messages in a

View File

@ -19,9 +19,17 @@ package android.view.translation;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.UiThread; import android.annotation.UiThread;
import android.view.View; import android.view.View;
import android.view.contentcapture.ContentCaptureSession;
/** /**
* Callback for handling the translated information show or hide in the {@link View}. * <p> Callback for handling the translated information show or hide in the {@link View}.
*
* <p> 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 @UiThread
public interface ViewTranslationCallback { public interface ViewTranslationCallback {
@ -33,13 +41,24 @@ public interface ViewTranslationCallback {
* method will not be called before {@link View#onViewTranslationResponse} or * method will not be called before {@link View#onViewTranslationResponse} or
* {@link View#onVirtualViewTranslationResponses}. * {@link View#onVirtualViewTranslationResponses}.
* *
* <p> 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.
*
* <p> 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. * See {@link View#onViewTranslationResponse} for how to get the translated information.
* *
* @return {@code true} if the View handles showing the translation. * @return {@code true} if the View handles showing the translation.
*/ */
boolean onShowTranslation(@NonNull View view); 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 * method will not be called before {@link View#onViewTranslationResponse} or
* {@link View#onViewTranslationResponse}. * {@link View#onViewTranslationResponse}.
* *
@ -47,7 +66,8 @@ public interface ViewTranslationCallback {
*/ */
boolean onHideTranslation(@NonNull View view); 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. * @return {@code true} if the View handles clearing the translation.
*/ */

View File

@ -739,6 +739,16 @@ public class RemoteViews implements Parcelable, Filter {
return mContextForResources.getPackageName(); return mContextForResources.getPackageName();
} }
@Override
public UserHandle getUser() {
return mContextForResources.getUser();
}
@Override
public int getUserId() {
return mContextForResources.getUserId();
}
@Override @Override
public boolean isRestricted() { public boolean isRestricted() {
// Override isRestricted and direct to resource's implementation. The isRestricted is // Override isRestricted and direct to resource's implementation. The isRestricted is

View File

@ -64,13 +64,24 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/ */
@Override @Override
public boolean onShowTranslation(@NonNull View view) { 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(); ViewTranslationResponse response = view.getViewTranslationResponse();
if (response == null) { if (response == null) {
Log.e(TAG, "onShowTranslation() shouldn't be called before " Log.e(TAG, "onShowTranslation() shouldn't be called before "
+ "onViewTranslationResponse()."); + "onViewTranslationResponse().");
return false; 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 = TransformationMethod originalTranslationMethod =
((TextView) view).getTransformationMethod(); ((TextView) view).getTransformationMethod();
mTranslationTransformation = new TranslationTransformationMethod(response, mTranslationTransformation = new TranslationTransformationMethod(response,
@ -147,7 +158,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
return true; return true;
} }
boolean isShowingTranslation() { public boolean isShowingTranslation() {
return mIsShowingTranslation; return mIsShowingTranslation;
} }

View File

@ -88,4 +88,9 @@ oneway interface ITaskOrganizer {
* user has pressed back on the root activity of a task controlled by the task organizer. * user has pressed back on the root activity of a task controlled by the task organizer.
*/ */
void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo); void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called when the IME has drawn on the organized task.
*/
void onImeDrawnOnTask(int taskId);
} }

View File

@ -144,6 +144,10 @@ public class TaskOrganizer extends WindowOrganizer {
@BinderThread @BinderThread
public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} 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. * Creates a persistent root task in WM for a particular windowing-mode.
* @param displayId The display to create the root task on. * @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) { public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info)); mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info));
} }
@Override
public void onImeDrawnOnTask(int taskId) {
mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId));
}
}; };
private ITaskOrganizerController getController() { private ITaskOrganizerController getController() {

View File

@ -26,7 +26,6 @@ import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder;
import android.view.WindowManager; import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
@ -67,7 +66,7 @@ public class WindowContext extends ContextWrapper {
mType = type; mType = type;
mOptions = options; mOptions = options;
mWindowManager = createWindowContextWindowManager(this); mWindowManager = createWindowContextWindowManager(this);
IBinder token = getWindowContextToken(); WindowTokenClient token = (WindowTokenClient) getWindowContextToken();
mController = new WindowContextController(token); mController = new WindowContextController(token);
Reference.reachabilityFence(this); Reference.reachabilityFence(this);

View File

@ -19,6 +19,7 @@ package android.window;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@ -46,7 +47,7 @@ public class WindowContextController {
@VisibleForTesting @VisibleForTesting
public boolean mAttachedToDisplayArea; public boolean mAttachedToDisplayArea;
@NonNull @NonNull
private final IBinder mToken; private final WindowTokenClient mToken;
/** /**
* Window Context Controller constructor * 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 * @param token The token used to attach to a window manager node. It is usually from
* {@link Context#getWindowContextToken()}. * {@link Context#getWindowContextToken()}.
*/ */
public WindowContextController(@NonNull IBinder token) { public WindowContextController(@NonNull WindowTokenClient token) {
mToken = token; this(token, WindowManagerGlobal.getWindowManagerService());
mWms = WindowManagerGlobal.getWindowManagerService();
} }
/** Used for test only. DO NOT USE it in production code. */ /** Used for test only. DO NOT USE it in production code. */
@VisibleForTesting @VisibleForTesting
public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) { public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
mToken = token; mToken = token;
mWms = mockWms; mWms = mockWms;
} }
@ -81,8 +81,14 @@ public class WindowContextController {
+ "a DisplayArea once."); + "a DisplayArea once.");
} }
try { try {
mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId, final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
options); 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) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@ -24,6 +24,8 @@ import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
/** /**
@ -33,7 +35,7 @@ import java.lang.ref.WeakReference;
* {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}. * {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}.
* *
* @see WindowContext * @see WindowContext
* @see android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, Bundle) * @see android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, Bundle)
* *
* @hide * @hide
*/ */
@ -50,8 +52,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
* can only attach one {@link Context}. * can only attach one {@link Context}.
* <p>This method must be called before invoking * <p>This method must be called before invoking
* {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, * {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
* Bundle, boolean)}.<p/> * Bundle)}.<p/>
* *
* @param context context to be attached * @param context context to be attached
* @throws IllegalStateException if attached context has already existed. * @throws IllegalStateException if attached context has already existed.
@ -63,6 +65,13 @@ public class WindowTokenClient extends IWindowToken.Stub {
mContextRef = new WeakReference<>(context); 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 @Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
final Context context = mContextRef.get(); final Context context = mContextRef.get();

View File

@ -72,17 +72,19 @@ public class SuspendedAppActivity extends AlertActivity
private Resources mSuspendingAppResources; private Resources mSuspendingAppResources;
private SuspendDialogInfo mSuppliedDialogInfo; private SuspendDialogInfo mSuppliedDialogInfo;
private Bundle mOptions; private Bundle mOptions;
private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() { private BroadcastReceiver mSuspendModifiedReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) { if (Intent.ACTION_PACKAGES_SUSPENSION_CHANGED.equals(intent.getAction())) {
final String[] unsuspended = intent.getStringArrayExtra( // Suspension conditions were modified, dismiss any related visible dialogs.
final String[] modified = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_PACKAGE_LIST); Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) { if (ArrayUtils.contains(modified, mSuspendedPackage)) {
if (!isFinishing()) { if (!isFinishing()) {
Slog.w(TAG, "Package " + mSuspendedPackage Slog.w(TAG, "Package " + mSuspendedPackage + " has modified"
+ " got unsuspended while the dialog was visible. Finishing."); + " suspension conditions while dialog was visible. Finishing.");
SuspendedAppActivity.this.finish(); 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(); setupAlert();
final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED); final IntentFilter suspendModifiedFilter =
registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null, new IntentFilter(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED);
null); registerReceiverAsUser(mSuspendModifiedReceiver, UserHandle.of(mUserId),
suspendModifiedFilter, null, null);
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
unregisterReceiver(mUnsuspendReceiver); unregisterReceiver(mSuspendModifiedReceiver);
} }
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) { private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {

View File

@ -165,7 +165,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
// Now fetch app icon and raster with no badging even in work profile // Now fetch app icon and raster with no badging even in work profile
Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info) Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
.getIconBitmap(android.os.Process.myUserHandle()); .getIconBitmap(mContext.getUser());
// Raster target drawable with appIcon as a badge // Raster target drawable with appIcon as a badge
SimpleIconFactory sif = SimpleIconFactory.obtain(mContext); SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);

View File

@ -50,6 +50,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;
/** /**
* A class that allows the app to get the frame metrics from HardwareRendererObserver. * 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 boolean mCancelled = false;
private FrameTrackerListener mListener; private FrameTrackerListener mListener;
private boolean mTracingStarted = false; private boolean mTracingStarted = false;
private Runnable mWaitForFinishTimedOut;
private static class JankInfo { private static class JankInfo {
long frameVsyncId; long frameVsyncId;
@ -263,10 +265,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
if (mListener != null) { if (mListener != null) {
mListener.onCujEvents(mSession, ACTION_SESSION_END); 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) { private void finish(int indexOnOrAfterEnd) {
mHandler.removeCallbacks(mWaitForFinishTimedOut);
mWaitForFinishTimedOut = null;
mMetricsFinalized = true; mMetricsFinalized = true;
// The tracing has been ended, remove the observer, see if need to trigger perfetto. // 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) { if (DEBUG) {
Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName() Log.i(TAG, "finish: CUJ=" + mSession.getName()
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")" + " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
+ " totalFrames=" + totalFramesCount + " totalFrames=" + totalFramesCount
+ " missedAppFrames=" + missedAppFramesCount + " missedAppFrames=" + missedAppFramesCount

View File

@ -103,7 +103,7 @@ public class InteractionJankMonitor {
private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName(); private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker"; 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_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY = private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =

View File

@ -707,6 +707,10 @@ public class BatteryStatsImpl extends BatteryStats {
* Mapping isolated uids to the actual owning app uid. * Mapping isolated uids to the actual owning app uid.
*/ */
final SparseIntArray mIsolatedUids = new SparseIntArray(); final SparseIntArray mIsolatedUids = new SparseIntArray();
/**
* Internal reference count of isolated uids.
*/
final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray();
/** /**
* The statistics we have collected organized by uids. * The statistics we have collected organized by uids.
@ -3897,6 +3901,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void addIsolatedUidLocked(int isolatedUid, int appUid, public void addIsolatedUidLocked(int isolatedUid, int appUid,
long elapsedRealtimeMs, long uptimeMs) { long elapsedRealtimeMs, long uptimeMs) {
mIsolatedUids.put(isolatedUid, appUid); mIsolatedUids.put(isolatedUid, appUid);
mIsolatedUidRefCounts.put(isolatedUid, 1);
final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs); final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
u.addIsolatedUid(isolatedUid); 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) * @see #scheduleRemoveIsolatedUidLocked(int, int)
*
* @return true if the isolated uid is actually removed.
*/ */
@GuardedBy("this") @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); final int idx = mIsolatedUids.indexOfKey(isolatedUid);
if (idx >= 0) { if (idx >= 0) {
final int ownerUid = mIsolatedUids.valueAt(idx); final int ownerUid = mIsolatedUids.valueAt(idx);
final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs); final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
u.removeIsolatedUid(isolatedUid); u.removeIsolatedUid(isolatedUid);
mIsolatedUids.removeAt(idx); mIsolatedUids.removeAt(idx);
mIsolatedUidRefCounts.delete(isolatedUid);
} else {
Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")");
} }
mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs)); 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) { 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, public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) { int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
uid = mapUid(uid); final int mappedUid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) { if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks // Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep. // will be canceled when the user puts the screen to sleep.
@ -4297,9 +4334,9 @@ public class BatteryStatsImpl extends BatteryStats {
} }
if (mRecordAllHistory) { if (mRecordAllHistory) {
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
uid, 0)) { mappedUid, 0)) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid); HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid);
} }
} }
if (mWakeLockNesting == 0) { if (mWakeLockNesting == 0) {
@ -4308,7 +4345,7 @@ public class BatteryStatsImpl extends BatteryStats {
+ Integer.toHexString(mHistoryCur.states)); + Integer.toHexString(mHistoryCur.states));
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName; mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
mWakeLockImportant = !unimportantForLogging; mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
} else if (!mWakeLockImportant && !unimportantForLogging } else if (!mWakeLockImportant && !unimportantForLogging
@ -4318,14 +4355,19 @@ public class BatteryStatsImpl extends BatteryStats {
mHistoryLastWritten.wakelockTag = null; mHistoryLastWritten.wakelockTag = null;
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName; mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
} }
mWakeLockImportant = true; mWakeLockImportant = true;
} }
mWakeLockNesting++; 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()) { if (mOnBatteryScreenOffTimeBase.isRunning()) {
// We only update the cpu time when a wake lock is acquired if the screen is off. // 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. // If the screen is on, we don't distribute the power amongst partial wakelocks.
@ -4335,7 +4377,7 @@ public class BatteryStatsImpl extends BatteryStats {
requestWakelockCpuUpdate(); requestWakelockCpuUpdate();
} }
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs); .noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
if (wc != null) { if (wc != null) {
@ -4343,8 +4385,8 @@ public class BatteryStatsImpl extends BatteryStats {
wc.getTags(), getPowerManagerWakeLockLevel(type), name, wc.getTags(), getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
} else { } else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
null, getPowerManagerWakeLockLevel(type), name, mappedUid, null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); 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, public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, long elapsedRealtimeMs, long uptimeMs) { int type, long elapsedRealtimeMs, long uptimeMs) {
uid = mapUid(uid); final int mappedUid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) { if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--; mWakeLockNesting--;
if (mRecordAllHistory) { if (mRecordAllHistory) {
@ -4366,9 +4408,9 @@ public class BatteryStatsImpl extends BatteryStats {
historyName = name; historyName = name;
} }
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
uid, 0)) { mappedUid, 0)) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid); HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid);
} }
} }
if (mWakeLockNesting == 0) { if (mWakeLockNesting == 0) {
@ -4380,7 +4422,7 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
} }
} }
if (uid >= 0) { if (mappedUid >= 0) {
if (mOnBatteryScreenOffTimeBase.isRunning()) { if (mOnBatteryScreenOffTimeBase.isRunning()) {
if (DEBUG_ENERGY_CPU) { if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Updating cpu time because of -wake_lock"); Slog.d(TAG, "Updating cpu time because of -wake_lock");
@ -4388,17 +4430,22 @@ public class BatteryStatsImpl extends BatteryStats {
requestWakelockCpuUpdate(); requestWakelockCpuUpdate();
} }
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs); .noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
if (wc != null) { if (wc != null) {
FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
wc.getTags(), getPowerManagerWakeLockLevel(type), name, wc.getTags(), getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
} else { } else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
null, getPowerManagerWakeLockLevel(type), name, mappedUid, null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); 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. * inactive so can be dropped.
*/ */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public boolean reset(long uptimeUs, long realtimeUs) { public boolean reset(long uptimeUs, long realtimeUs, int resetReason) {
boolean active = false; boolean active = false;
mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs); mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs);
@ -8641,7 +8688,11 @@ public class BatteryStatsImpl extends BatteryStats {
resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs); resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs);
resetIfNotNull(mModemControllerActivity, 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(mUserCpuTime, false, realtimeUs);
resetIfNotNull(mSystemCpuTime, false, realtimeUs); resetIfNotNull(mSystemCpuTime, false, realtimeUs);
@ -11324,7 +11375,7 @@ public class BatteryStatsImpl extends BatteryStats {
mNumConnectivityChange = 0; mNumConnectivityChange = 0;
for (int i=0; i<mUidStats.size(); i++) { for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs)) { if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs, resetReason)) {
mUidStats.valueAt(i).detachFromTimeBase(); mUidStats.valueAt(i).detachFromTimeBase();
mUidStats.remove(mUidStats.keyAt(i)); mUidStats.remove(mUidStats.keyAt(i));
i--; i--;
@ -16761,6 +16812,15 @@ public class BatteryStatsImpl extends BatteryStats {
pw.print("UIDs removed since the later of device start or stats reset: "); pw.print("UIDs removed since the later of device start or stats reset: ");
pw.println(mNumUidsRemoved); pw.println(mNumUidsRemoved);
pw.println("Currently mapped isolated uids:");
final int numIsolatedUids = mIsolatedUids.size();
for (int i = 0; i < numIsolatedUids; i++) {
final int isolatedUid = mIsolatedUids.keyAt(i);
final int ownerUid = mIsolatedUids.valueAt(i);
final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
pw.println(" " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
}
pw.println(); pw.println();
dumpConstantsLocked(pw); dumpConstantsLocked(pw);

View File

@ -29,6 +29,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -234,8 +235,9 @@ public class BatteryUsageStatsProvider {
final boolean includePowerModels = (query.getFlags() final boolean includePowerModels = (query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames();
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
mStats.getCustomEnergyConsumerNames(), includePowerModels); customEnergyConsumerNames, includePowerModels);
if (mBatteryUsageStatsStore == null) { if (mBatteryUsageStatsStore == null) {
Log.e(TAG, "BatteryUsageStatsStore is unavailable"); Log.e(TAG, "BatteryUsageStatsStore is unavailable");
return builder.build(); return builder.build();
@ -247,7 +249,14 @@ public class BatteryUsageStatsProvider {
final BatteryUsageStats snapshot = final BatteryUsageStats snapshot =
mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp); mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
if (snapshot != null) { 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()));
}
} }
} }
} }

View File

@ -21,13 +21,18 @@ import android.os.BatteryStats;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery; import android.os.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer; import android.os.UidBatteryConsumer;
import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import java.util.Arrays;
/** /**
* Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type * Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type
* {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). * {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
*/ */
public class CustomMeasuredPowerCalculator extends PowerCalculator { public class CustomMeasuredPowerCalculator extends PowerCalculator {
private static final String TAG = "CustomMeasuredPowerCalc";
public CustomMeasuredPowerCalculator(PowerProfile powerProfile) { public CustomMeasuredPowerCalculator(PowerProfile powerProfile) {
} }
@ -76,9 +81,9 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator {
if (totalPowerMah == null) { if (totalPowerMah == null) {
newTotalPowerMah = new double[customMeasuredPowerMah.length]; newTotalPowerMah = new double[customMeasuredPowerMah.length];
} else if (totalPowerMah.length != customMeasuredPowerMah.length) { } else if (totalPowerMah.length != customMeasuredPowerMah.length) {
newTotalPowerMah = new double[customMeasuredPowerMah.length]; Slog.wtf(TAG, "Number of custom energy components is not the same for all apps: "
System.arraycopy(totalPowerMah, 0, newTotalPowerMah, 0, + totalPowerMah.length + ", " + customMeasuredPowerMah.length);
customMeasuredPowerMah.length); newTotalPowerMah = Arrays.copyOf(totalPowerMah, customMeasuredPowerMah.length);
} else { } else {
newTotalPowerMah = totalPowerMah; newTotalPowerMah = totalPowerMah;
} }

View File

@ -215,6 +215,9 @@ public class WifiPowerCalculator extends PowerCalculator {
+ "ms tx=" + txTime + "ms power=" + formatCharge( + "ms tx=" + txTime + "ms power=" + formatCharge(
powerDurationAndTraffic.powerMah)); powerDurationAndTraffic.powerMah));
} }
} else {
powerDurationAndTraffic.durationMs = 0;
powerDurationAndTraffic.powerMah = 0;
} }
} else { } else {
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000; final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;

View File

@ -124,7 +124,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try { try {
sendCloseSystemWindows();
mContext.startActivity(intent); mContext.startActivity(intent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
startCallActivity(); startCallActivity();
@ -147,7 +146,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
dispatcher.performedLongPress(event); dispatcher.performedLongPress(event);
if (isUserSetupComplete()) { if (isUserSetupComplete()) {
mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
sendCloseSystemWindows();
// Broadcast an intent that the Camera button was longpressed // Broadcast an intent that the Camera button was longpressed
Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@ -178,7 +176,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try { try {
mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
sendCloseSystemWindows();
getSearchManager().stopSearch(); getSearchManager().stopSearch();
mContext.startActivity(intent); mContext.startActivity(intent);
// Only clear this if we successfully start the // Only clear this if we successfully start the
@ -272,7 +269,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
@UnsupportedAppUsage @UnsupportedAppUsage
void startCallActivity() { void startCallActivity() {
sendCloseSystemWindows();
Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try { try {
@ -319,10 +315,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
return mMediaSessionManager; return mMediaSessionManager;
} }
void sendCloseSystemWindows() {
PhoneWindow.sendCloseSystemWindows(mContext, null);
}
private void handleVolumeKeyEvent(KeyEvent keyEvent) { private void handleVolumeKeyEvent(KeyEvent keyEvent) {
getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent, getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent,
AudioManager.USE_DEFAULT_STREAM_TYPE); AudioManager.USE_DEFAULT_STREAM_TYPE);

View File

@ -148,7 +148,7 @@ oneway interface IStatusBar
*/ */
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, 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. * Used to notify the authentication dialog that a biometric has been authenticated.
*/ */

View File

@ -110,7 +110,8 @@ interface IStatusBarService
// Used to show the authentication dialog (Biometrics, Device Credential) // Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, 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 // Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated(); void onBiometricAuthenticated();

View File

@ -291,10 +291,10 @@ public class ContrastColorUtil {
* Finds a suitable color such that there's enough contrast. * Finds a suitable color such that there's enough contrast.
* *
* @param color the color to start searching from. * @param color the color to start searching from.
* @param other the color to ensure contrast against. Assumed to be lighter than {@param color} * @param other the color to ensure contrast against. Assumed to be lighter than {@code color}
* @param findFg if true, we assume {@param color} is a foreground, otherwise a background. * @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
* @param minRatio the minimum contrast ratio required. * @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. * contrast ratio.
*/ */
public static int findContrastColor(int color, int other, boolean findFg, double minRatio) { 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 color the color to start searching from.
* @param backgroundColor the color to ensure contrast against. * @param backgroundColor the color to ensure contrast against.
* @param minRatio the minimum contrast ratio required. * @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) { public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
int fg = color; int fg = color;
@ -361,10 +361,10 @@ public class ContrastColorUtil {
* Finds a suitable color such that there's enough contrast. * Finds a suitable color such that there's enough contrast.
* *
* @param color the color to start searching from. * @param color the color to start searching from.
* @param other the color to ensure contrast against. Assumed to be darker than {@param color} * @param other the color to ensure contrast against. Assumed to be darker than {@code color}
* @param findFg if true, we assume {@param color} is a foreground, otherwise a background. * @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
* @param minRatio the minimum contrast ratio required. * @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. * contrast ratio.
*/ */
public static int findContrastColorAgainstDark(int color, int other, boolean findFg, public static int findContrastColorAgainstDark(int color, int other, boolean findFg,
@ -393,7 +393,8 @@ public class ContrastColorUtil {
low = l; low = l;
} }
} }
return findFg ? fg : bg; hsl[2] = high;
return ColorUtilsFromCompat.HSLToColor(hsl);
} }
public static int ensureTextContrastOnBlack(int color) { 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) { public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
if (color == Notification.COLOR_DEFAULT) { if (color == Notification.COLOR_DEFAULT) {

View File

@ -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 *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
per-file Protocol* = etancohen@google.com, lorenzo@google.com per-file Protocol* = etancohen@google.com, lorenzo@google.com
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file DataClass* = eugenesusla@google.com

View File

@ -17,6 +17,7 @@
package com.android.internal.widget; package com.android.internal.widget;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; 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;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 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 * @see StrongAuthTracker#isTrustAllowedForUser
*/ */

View File

@ -53,6 +53,8 @@ public class NotificationActionListLayout extends LinearLayout {
private int mEmphasizedHeight; private int mEmphasizedHeight;
private int mRegularHeight; private int mRegularHeight;
@DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start; @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
int mNumNotGoneChildren;
int mNumPriorityChildren;
public NotificationActionListLayout(Context context, AttributeSet attrs) { public NotificationActionListLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0); this(context, attrs, 0);
@ -76,15 +78,14 @@ public class NotificationActionListLayout extends LinearLayout {
&& ((EmphasizedNotificationButton) actionView).isPriority(); && ((EmphasizedNotificationButton) actionView).isPriority();
} }
@Override private void countAndRebuildMeasureOrder() {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int numChildren = getChildCount();
final int N = getChildCount();
int textViews = 0; int textViews = 0;
int otherViews = 0; int otherViews = 0;
int notGoneChildren = 0; mNumNotGoneChildren = 0;
int priorityChildren = 0; mNumPriorityChildren = 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < numChildren; i++) {
View c = getChildAt(i); View c = getChildAt(i);
if (c instanceof TextView) { if (c instanceof TextView) {
textViews++; textViews++;
@ -92,9 +93,9 @@ public class NotificationActionListLayout extends LinearLayout {
otherViews++; otherViews++;
} }
if (c.getVisibility() != GONE) { if (c.getVisibility() != GONE) {
notGoneChildren++; mNumNotGoneChildren++;
if (isPriority(c)) { if (isPriority(c)) {
priorityChildren++; mNumPriorityChildren++;
} }
} }
} }
@ -119,17 +120,20 @@ public class NotificationActionListLayout extends LinearLayout {
if (needRebuild) { if (needRebuild) {
rebuildMeasureOrder(textViews, otherViews); rebuildMeasureOrder(textViews, otherViews);
} }
}
private int measureAndGetUsedWidth(int widthMeasureSpec, int heightMeasureSpec, int innerWidth,
boolean collapsePriorityActions) {
final int numChildren = getChildCount();
final boolean constrained = final boolean constrained =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED; MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
final int otherSize = mMeasureOrderOther.size(); final int otherSize = mMeasureOrderOther.size();
int usedWidth = 0; int usedWidth = 0;
int maxPriorityWidth = 0;
int measuredChildren = 0; int measuredChildren = 0;
int measuredPriorityChildren = 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 // Measure shortest children first. To avoid measuring twice, we approximate by looking
// at the text length. // at the text length.
final boolean isPriority; 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 // measure in the order of (approx.) size, a large view can still take more than its
// share if the others are small. // share if the others are small.
int availableWidth = innerWidth - usedWidth; int availableWidth = innerWidth - usedWidth;
int unmeasuredChildren = notGoneChildren - measuredChildren; int unmeasuredChildren = mNumNotGoneChildren - measuredChildren;
int maxWidthForChild = availableWidth / unmeasuredChildren; 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: // Priority children get a larger maximum share of the total space:
// maximum priority share = (nPriority + 1) / (MAX + 1) // maximum priority share = (nPriority + 1) / (MAX + 1)
int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren; int unmeasuredPriorityChildren = mNumPriorityChildren
- measuredPriorityChildren;
int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren; int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
/ (Notification.MAX_ACTION_BUTTONS + 1); / (Notification.MAX_ACTION_BUTTONS + 1);
@ -187,6 +199,19 @@ public class NotificationActionListLayout extends LinearLayout {
} else { } else {
mExtraStartPadding = 0; 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; mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding;
setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec), setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),

Some files were not shown because too many files have changed in this diff Show More