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();
}
reportTempWhitelistChangedLocked(uid, true);
} else {
// The uid is already temp allowlisted, only need to update AMS for temp allowlist
// duration.
if (mLocalActivityManager != null) {
mLocalActivityManager.updateDeviceIdleTempAllowlist(null, uid, true,
duration, tempAllowListType, reasonCode, reason, callingUid);
}
}
}
if (informWhitelistChanged) {
@ -3941,6 +3948,10 @@ public class DeviceIdleController extends SystemService
if (idleUntil) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else if (mState == STATE_LOCATING) {
// Use setExact so we don't keep the GPS active for too long.
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
if (mConstants.USE_WINDOW_ALARMS) {
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,

View File

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

View File

@ -52,9 +52,8 @@
#include <gui/DisplayEventReceiver.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/eglext.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 int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
static constexpr size_t TEXT_POS_LEN_MAX = 16;
static const int DYNAMIC_COLOR_COUNT = 4;
static const char U_TEXTURE[] = "uTexture";
static const char U_FADE[] = "uFade";
static const char U_CROP_AREA[] = "uCropArea";
static const char U_START_COLOR_PREFIX[] = "uStartColor";
static const char U_END_COLOR_PREFIX[] = "uEndColor";
static const char U_COLOR_PROGRESS[] = "uColorProgress";
static const char A_UV[] = "aUv";
static const char A_POSITION[] = "aPosition";
static const char VERTEX_SHADER_SOURCE[] = R"(
precision mediump float;
attribute vec4 aPosition;
attribute highp vec2 aUv;
varying highp vec2 vUv;
void main() {
gl_Position = aPosition;
vUv = aUv;
})";
static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
precision mediump float;
const float cWhiteMaskThreshold = 0.05;
uniform sampler2D uTexture;
uniform float uFade;
uniform float uColorProgress;
uniform vec4 uStartColor0;
uniform vec4 uStartColor1;
uniform vec4 uStartColor2;
uniform vec4 uStartColor3;
uniform vec4 uEndColor0;
uniform vec4 uEndColor1;
uniform vec4 uEndColor2;
uniform vec4 uEndColor3;
varying highp vec2 vUv;
void main() {
vec4 mask = texture2D(uTexture, vUv);
float r = mask.r;
float g = mask.g;
float b = mask.b;
float a = mask.a;
// If all channels have values, render pixel as a shade of white.
float useWhiteMask = step(cWhiteMaskThreshold, r)
* step(cWhiteMaskThreshold, g)
* step(cWhiteMaskThreshold, b)
* step(cWhiteMaskThreshold, a);
vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress)
+ g * mix(uStartColor1, uEndColor1, uColorProgress)
+ b * mix(uStartColor2, uEndColor2, uColorProgress)
+ a * mix(uStartColor3, uEndColor3, uColorProgress);
color = mix(color, vec4(vec3((r + g + b + a) * 0.25), 1.0), useWhiteMask);
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
uniform sampler2D uTexture;
uniform float uFade;
varying highp vec2 vUv;
void main() {
vec4 color = texture2D(uTexture, vUv);
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
uniform sampler2D uTexture;
uniform vec4 uCropArea;
varying highp vec2 vUv;
void main() {
vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x),
mix(uCropArea.y, uCropArea.w, vUv.y));
gl_FragColor = texture2D(uTexture, uv);
})";
static GLfloat quadPositions[] = {
-0.5f, -0.5f,
+0.5f, -0.5f,
+0.5f, +0.5f,
+0.5f, +0.5f,
-0.5f, +0.5f,
-0.5f, -0.5f
};
static GLfloat quadUVs[] = {
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f
};
// ---------------------------------------------------------------------------
@ -163,7 +249,8 @@ void BootAnimation::binderDied(const wp<IBinder>&) {
requestExit();
}
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) {
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo,
bool premultiplyAlpha) {
AImageDecoder* decoder = nullptr;
AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
if (!decoder) {
@ -177,6 +264,10 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
outInfo->stride = AImageDecoder_getMinimumStride(decoder);
outInfo->flags = 0;
if (!premultiplyAlpha) {
AImageDecoder_setUnpremultipliedRequired(decoder, true);
}
const size_t size = outInfo->stride * outInfo->height;
void* pixels = malloc(size);
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
@ -190,13 +281,14 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
}
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const char* name) {
const char* name, bool premultiplyAlpha) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
if (asset == nullptr)
return NO_INIT;
AndroidBitmapInfo bitmapInfo;
void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo);
void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo,
premultiplyAlpha);
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
asset->close();
@ -209,7 +301,6 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const int w = bitmapInfo.width;
const int h = bitmapInfo.height;
GLint crop[4] = { 0, h, w, -h };
texture->w = w;
texture->h = h;
@ -237,18 +328,19 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
break;
}
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return NO_ERROR;
}
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
bool premultiplyAlpha) {
AndroidBitmapInfo bitmapInfo;
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo);
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
premultiplyAlpha);
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
// FileMap memory is never released until application exit.
@ -263,7 +355,6 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
const int w = bitmapInfo.width;
const int h = bitmapInfo.height;
GLint crop[4] = { 0, h, w, -h };
int tw = 1 << (31 - __builtin_clz(w));
int th = 1 << (31 - __builtin_clz(h));
if (tw < w) tw <<= 1;
@ -297,7 +388,10 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
break;
}
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
*width = w;
*height = h;
@ -470,7 +564,9 @@ status_t BootAnimation::readyToRun() {
eglInitialize(display, nullptr, nullptr);
EGLConfig config = getEglConfig(display);
EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
// Initialize egl context with client version number 2.0.
EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
EGLint w, h;
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@ -503,11 +599,6 @@ status_t BootAnimation::readyToRun() {
void BootAnimation::projectSceneToWindow() {
glViewport(0, 0, mWidth, mHeight);
glScissor(0, 0, mWidth, mHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void BootAnimation::resizeSurface(int newWidth, int newHeight) {
@ -600,8 +691,76 @@ void BootAnimation::findBootAnimationFile() {
}
}
GLuint compileShader(GLenum shaderType, const GLchar *source) {
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE) {
SLOGE("Compile shader failed. Shader type: %d", shaderType);
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<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 result;
initShaders();
// We have no bootanimation file, so we use the stock android logo
// animation.
if (mZipFileName.isEmpty()) {
@ -623,6 +782,8 @@ bool BootAnimation::threadLoop() {
}
bool BootAnimation::android() {
glActiveTexture(GL_TEXTURE0);
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
elapsedRealtime());
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
@ -631,19 +792,16 @@ bool BootAnimation::android() {
mCallbacks->init({});
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glUseProgram(mImageShader);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const nsecs_t startTime = systemTime();
do {
@ -666,12 +824,12 @@ bool BootAnimation::android() {
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h);
drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE)
@ -766,6 +924,20 @@ static bool parseColor(const char str[7], float color[3]) {
return true;
}
// Parse a color represented as a signed decimal int string.
// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
// If the input color string is empty, set color with values in defaultColor.
static void parseColorDecimalString(const std::string& colorString,
float color[3], float defaultColor[3]) {
if (colorString == "") {
memcpy(color, defaultColor, sizeof(float) * 3);
return;
}
int colorInt = atoi(colorString.c_str());
color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
}
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
ZipEntryRO entry = zip->findEntryByName(name);
@ -798,10 +970,10 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
status = initTexture(font->map, &font->texture.w, &font->texture.h);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else if (fallback != nullptr) {
status = initTexture(&font->texture, mAssets, fallback);
} else {
@ -816,40 +988,11 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
return status;
}
void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth,
const int frameHeight, const Animation::Part& part,
const int fadedFramesCount) {
glEnable(GL_BLEND);
glEnableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
// avoid creating a hole due to mixing result alpha with GL_REPLACE texture
glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
const float alpha = static_cast<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) {
glEnable(GL_BLEND); // Allow us to draw on top of the animation
glBindTexture(GL_TEXTURE_2D, font.texture.name);
glUseProgram(mTextShader);
glUniform1i(mTextTextureLocation, 0);
const int len = strlen(str);
const int strWidth = font.char_width * len;
@ -865,8 +1008,6 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int*
*y = mHeight + *y - font.char_height;
}
int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
for (int i = 0; i < len; i++) {
char c = str[i];
@ -878,13 +1019,13 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int*
const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters
const int row = charPos / FONT_NUM_COLS;
const int col = charPos % FONT_NUM_COLS;
cropRect[0] = col * font.char_width; // Left of column
cropRect[1] = row * font.char_height * 2; // Top of row
// Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
cropRect[1] += bold ? 2 * font.char_height : font.char_height;
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
// Bold fonts are expected in the second half of each row.
float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS;
float u0 = ((float)col) / FONT_NUM_COLS;
float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
float u1 = u0 + 1.0f / FONT_NUM_COLS;
glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
drawTexturedQuad(*x, *y, font.char_width, font.char_height);
*x += font.char_width;
}
@ -938,6 +1079,8 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
return false;
}
char const* s = desString.string();
std::string dynamicColoringPartName = "";
bool postDynamicColoring = false;
// Parse the description file
for (;;) {
@ -952,11 +1095,19 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
int pause = 0;
int progress = 0;
int framesToFadeCount = 0;
int colorTransitionStart = 0;
int colorTransitionEnd = 0;
char path[ANIM_ENTRY_NAME_MAX];
char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
char pathType;
// start colors default to black if unspecified
char start_color_0[7] = "000000";
char start_color_1[7] = "000000";
char start_color_2[7] = "000000";
char start_color_3[7] = "000000";
int nextReadPos;
@ -971,6 +1122,18 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
} else {
animation.progressEnabled = false;
}
} else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s %d %d",
dynamicColoringPartNameBuffer,
start_color_0, start_color_1, start_color_2, start_color_3,
&colorTransitionStart, &colorTransitionEnd)) {
animation.dynamicColoringEnabled = true;
parseColor(start_color_0, animation.startColors[0]);
parseColor(start_color_1, animation.startColors[1]);
parseColor(start_color_2, animation.startColors[2]);
parseColor(start_color_3, animation.startColors[3]);
animation.colorTransitionStart = colorTransitionStart;
animation.colorTransitionEnd = colorTransitionEnd;
dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
if (pathType == 'f') {
@ -983,6 +1146,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
// "clockPos1=%s, clockPos2=%s",
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
Animation::Part part;
if (path == dynamicColoringPartName) {
// Part is specified to use dynamic coloring.
part.useDynamicColoring = true;
part.postDynamicColoring = false;
postDynamicColoring = true;
} else {
// Part does not use dynamic coloring.
part.useDynamicColoring = false;
part.postDynamicColoring = postDynamicColoring;
}
part.playUntilComplete = pathType == 'c';
part.framesToFadeCount = framesToFadeCount;
part.count = count;
@ -1166,19 +1339,16 @@ bool BootAnimation::movie() {
// Blend required to draw time on top of animation frames.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
bool clockFontInitialized = false;
if (mClockEnabled) {
clockFontInitialized =
@ -1193,6 +1363,10 @@ bool BootAnimation::movie() {
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
}
if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) {
initDynamicColors();
}
playAnimation(*mAnimation);
if (mTimeCheckThread != nullptr) {
@ -1218,6 +1392,55 @@ bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part,
(lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
}
// Linear mapping from range <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) {
const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
@ -1230,7 +1453,6 @@ bool BootAnimation::playAnimation(const Animation& animation) {
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
// Handle animation package
if (part.animation != nullptr) {
@ -1261,6 +1483,19 @@ bool BootAnimation::playAnimation(const Animation& animation) {
for (size_t j=0 ; j<fcount ; j++) {
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();
const int animationX = (mWidth - animation.width) / 2;
@ -1272,44 +1507,38 @@ bool BootAnimation::playAnimation(const Animation& animation) {
if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
if (part.count != 1) {
glGenTextures(1, &frame.tid);
glBindTexture(GL_TEXTURE_2D, frame.tid);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
int w, h;
initTexture(frame.map, &w, &h);
// Set decoding option to alpha unpremultiplied so that the R, G, B channels
// of transparent pixels are preserved.
initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
}
const int xc = animationX + frame.trimX;
const int yc = animationY + frame.trimY;
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
if (!clearReg.isEmpty()) {
Region::const_iterator head(clearReg.begin());
Region::const_iterator tail(clearReg.end());
glEnable(GL_SCISSOR_TEST);
while (head != tail) {
const Rect& r2(*head++);
glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
}
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight)
const int frameDrawY = mHeight - (yc + frame.trimHeight);
glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
float fade = 0;
// if the part hasn't been stopped yet then continue fading if necessary
if (exitPending() && part.hasFadingPhase()) {
fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
++fadedFramesCount);
fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount;
if (fadedFramesCount >= part.framesToFadeCount) {
fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
}
}
glUseProgram(mImageShader);
glUniform1i(mImageTextureLocation, 0);
glUniform1f(mImageFadeLocation, fade);
if (animation.dynamicColoringEnabled) {
glUniform1f(mImageColorProgressLocation, colorProgress);
}
glEnable(GL_BLEND);
drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
glDisable(GL_BLEND);
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);

View File

@ -31,7 +31,7 @@
#include <binder/IBinder.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <GLES2/gl2.h>
namespace android {
@ -53,7 +53,7 @@ public:
};
struct Font {
FileMap* map;
FileMap* map = nullptr;
Texture texture;
int char_width;
int char_height;
@ -62,7 +62,7 @@ public:
struct Animation {
struct Frame {
String8 name;
FileMap* map;
FileMap* map = nullptr;
int trimX;
int trimY;
int trimWidth;
@ -90,6 +90,10 @@ public:
uint8_t* audioData;
int audioLength;
Animation* animation;
// Controls if dynamic coloring is enabled for this part.
bool useDynamicColoring = false;
// Defines if this part is played after the dynamic coloring part.
bool postDynamicColoring = false;
bool hasFadingPhase() const {
return !playUntilComplete && framesToFadeCount > 0;
@ -105,6 +109,12 @@ public:
ZipFileRO* zip;
Font clockFont;
Font progressFont;
// Controls if dynamic coloring is enabled for the whole animation.
bool dynamicColoringEnabled = false;
int colorTransitionStart = 0; // Start frame of dynamic color transition.
int colorTransitionEnd = 0; // End frame of dynamic color transition.
float startColors[4][3]; // Start colors of dynamic color transition.
float endColors[4][3]; // End colors of dynamic color transition.
};
// All callbacks will be called from this class's internal thread.
@ -163,9 +173,12 @@ private:
int displayEventCallback(int fd, int events, void* data);
void processDisplayEvents();
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(FileMap* map, int* width, int* height);
status_t initTexture(Texture* texture, AssetManager& asset, const char* name,
bool premultiplyAlpha = true);
status_t initTexture(FileMap* map, int* width, int* height,
bool premultiplyAlpha = true);
status_t initFont(Font* font, const char* fallback);
void initShaders();
bool android();
bool movie();
void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
@ -173,6 +186,7 @@ private:
void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
const Animation::Part& part, int fadedFramesCount);
void drawTexturedQuad(float xStart, float yStart, float width, float height);
bool validClock(const Animation::Part& part);
Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&);
@ -192,6 +206,7 @@ private:
void checkExit();
void handleViewport(nsecs_t timestep);
void initDynamicColors();
sp<SurfaceComposerClient> mSession;
AssetManager mAssets;
@ -218,6 +233,13 @@ private:
sp<TimeCheckThread> mTimeCheckThread = nullptr;
sp<Callbacks> mCallbacks;
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
toddke@google.com
patb@google.com
zyy@google.com

View File

@ -771,6 +771,11 @@ public class ActivityManager {
return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
}
/** @hide Should this process state be considered in the cache? */
public static final boolean isProcStateCached(int procState) {
return procState >= PROCESS_STATE_CACHED_ACTIVITY;
}
/** @hide Is this a foreground service type? */
public static boolean isForegroundService(int procState) {
return procState == PROCESS_STATE_FOREGROUND_SERVICE;

View File

@ -156,6 +156,7 @@ public abstract class ActivityManagerInternal {
/**
* Update information about which app IDs are on the temp allowlist.
* @param appids the updated list of appIds in temp allowlist.
* If null, it is to update only changingUid.
* @param changingUid uid to add or remove to temp allowlist.
* @param adding true to add to temp allowlist, false to remove from temp allowlist.
* @param durationMs when adding is true, the duration to be in temp allowlist.
@ -165,7 +166,7 @@ public abstract class ActivityManagerInternal {
* @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
* is true.
*/
public abstract void updateDeviceIdleTempAllowlist(int[] appids, int changingUid,
public abstract void updateDeviceIdleTempAllowlist(@Nullable int[] appids, int changingUid,
boolean adding, long durationMs, @TempAllowListType int type,
@ReasonCode int reasonCode,
@Nullable String reason, int callingUid);

View File

@ -4906,7 +4906,8 @@ public final class ActivityThread extends ClientTransactionHandler
Slog.w(TAG, "Activity top position already set to onTop=" + onTop);
return;
}
throw new IllegalStateException("Activity top position already set to onTop=" + onTop);
// TODO(b/197484331): Remove this short-term workaround while fixing the binder failure.
Slog.e(TAG, "Activity top position already set to onTop=" + onTop);
}
r.isTopResumedActivity = onTop;

View File

@ -2735,10 +2735,13 @@ class ContextImpl extends Context {
// need to override their display in ResourcesManager.
baseContext.mForceDisplayOverrideInResources = false;
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
baseContext.mDisplay = display;
final Resources windowContextResources = createWindowContextResources(baseContext);
baseContext.setResources(windowContextResources);
// Associate the display with window context resources so that configuration update from
// the server side will also apply to the display's metrics.
baseContext.mDisplay = ResourcesManager.getInstance()
.getAdjustedDisplay(display.getDisplayId(), windowContextResources);
return baseContext;
}

View File

@ -135,6 +135,7 @@ public final class GameManager {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns a list of supported game modes for a given package.
* <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);
void setGameMode(String packageName, int gameMode, int userId);
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
* 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 title the title of the action
* @param intent the {@link PendingIntent} to fire when users trigger this action
@ -5387,8 +5395,8 @@ public class Notification implements Parcelable
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
// Use different highlighted colors for conversations' unread count
if (p.mHighlightExpander) {
pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor);
textColor = Colors.flattenAlpha(bgColor, pillColor);
pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor);
}
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@ -6121,21 +6129,22 @@ public class Notification implements Parcelable
if (emphasizedMode) {
// change the background bgColor
CharSequence title = action.title;
ColorStateList[] outResultColor = new ColorStateList[1];
int buttonFillColor = getColors(p).getSecondaryAccentColor();
if (isLegacy()) {
title = ContrastColorUtil.clearColorSpans(title);
} else {
// Check for a full-length span color to use as the button fill color.
Integer fullLengthColor = getFullLengthSpanColor(title);
if (fullLengthColor != null) {
// Ensure the custom button fill has 1.3:1 contrast w/ notification bg.
int notifBackgroundColor = getColors(p).getBackgroundColor();
title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor);
buttonFillColor = ensureButtonFillContrast(
fullLengthColor, notifBackgroundColor);
}
// Remove full-length color spans and ensure text contrast with the button fill.
title = ensureColorSpanContrast(title, buttonFillColor);
}
button.setTextViewText(R.id.action0, processTextSpans(title));
boolean hasColorOverride = outResultColor[0] != null;
if (hasColorOverride) {
// There's a span spanning the full text, let's take it and use it as the
// background color
buttonFillColor = outResultColor[0].getDefaultColor();
}
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
buttonFillColor, mInNightMode);
button.setTextColor(R.id.action0, textColor);
@ -6168,17 +6177,58 @@ public class Notification implements Parcelable
}
/**
* Ensures contrast on color spans against a background color. also returns the color of the
* text if a span was found that spans over the whole text.
* Extract the color from a full-length span from the text.
*
* @param charSequence the charSequence containing spans
* @return the raw color of the text's last full-length span containing a color, or null if
* no full-length span sets the text color.
* @hide
*/
@VisibleForTesting
@Nullable
public static Integer getFullLengthSpanColor(CharSequence charSequence) {
// NOTE: this method preserves the functionality that for a CharSequence with multiple
// full-length spans, the color of the last one is used.
Integer result = null;
if (charSequence instanceof Spanned) {
Spanned ss = (Spanned) charSequence;
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
// First read through all full-length spans to get the button fill color, which will
// be used as the background color for ensuring contrast of non-full-length spans.
for (Object span : spans) {
int spanStart = ss.getSpanStart(span);
int spanEnd = ss.getSpanEnd(span);
boolean fullLength = (spanEnd - spanStart) == charSequence.length();
if (!fullLength) {
continue;
}
if (span instanceof TextAppearanceSpan) {
TextAppearanceSpan originalSpan = (TextAppearanceSpan) span;
ColorStateList textColor = originalSpan.getTextColor();
if (textColor != null) {
result = textColor.getDefaultColor();
}
} else if (span instanceof ForegroundColorSpan) {
ForegroundColorSpan originalSpan = (ForegroundColorSpan) span;
result = originalSpan.getForegroundColor();
}
}
}
return result;
}
/**
* Ensures contrast on color spans against a background color.
* Note that any full-length color spans will be removed instead of being contrasted.
*
* @param charSequence the charSequence on which the spans are
* @param background the background color to ensure the contrast against
* @param outResultColor an array in which a color will be returned as the first element if
* there exists a full length color span.
* @return the contrasted charSequence
* @hide
*/
private static CharSequence ensureColorSpanContrast(CharSequence charSequence,
int background, ColorStateList[] outResultColor) {
@VisibleForTesting
public static CharSequence ensureColorSpanContrast(CharSequence charSequence,
int background) {
if (charSequence instanceof Spanned) {
Spanned ss = (Spanned) charSequence;
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
@ -6195,6 +6245,10 @@ public class Notification implements Parcelable
TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
ColorStateList textColor = originalSpan.getTextColor();
if (textColor != null) {
if (fullLength) {
// Let's drop the color from the span
textColor = null;
} else {
int[] colors = textColor.getColors();
int[] newColors = new int[colors.length];
for (int i = 0; i < newColors.length; i++) {
@ -6204,10 +6258,6 @@ public class Notification implements Parcelable
}
textColor = new ColorStateList(textColor.getStates().clone(),
newColors);
if (fullLength) {
outResultColor[0] = textColor;
// Let's drop the color from the span
textColor = null;
}
resultSpan = new TextAppearanceSpan(
originalSpan.getFamily(),
@ -6217,15 +6267,14 @@ public class Notification implements Parcelable
originalSpan.getLinkTextColor());
}
} else if (resultSpan instanceof ForegroundColorSpan) {
if (fullLength) {
resultSpan = null;
} else {
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
int foregroundColor = originalSpan.getForegroundColor();
boolean isBgDark = isColorDark(background);
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
foregroundColor, background, isBgDark);
if (fullLength) {
outResultColor[0] = ColorStateList.valueOf(foregroundColor);
resultSpan = null;
} else {
resultSpan = new ForegroundColorSpan(foregroundColor);
}
} else {
@ -6247,12 +6296,28 @@ public class Notification implements Parcelable
*
* @param color the color to check
* @return true if the color has higher contrast with white than black
* @hide
*/
private static boolean isColorDark(int color) {
public static boolean isColorDark(int color) {
// as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
}
/**
* Finds a button fill color with sufficient contrast over bg (1.3:1) that has the same hue
* as the original color, but is lightened or darkened depending on whether the background
* is dark or light.
*
* @hide
*/
@VisibleForTesting
public static int ensureButtonFillContrast(int color, int bg) {
return isColorDark(bg)
? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, 1.3)
: ContrastColorUtil.findContrastColor(color, bg, true, 1.3);
}
/**
* @return Whether we are currently building a notification from a legacy (an app that
* doesn't create material notifications by itself) app.
@ -6441,25 +6506,34 @@ public class Notification implements Parcelable
if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
&& !styleDisplaysCustomViewInline()) {
if (mN.contentView == null) {
mN.contentView = createContentView();
RemoteViews newContentView = mN.contentView;
RemoteViews newBigContentView = mN.bigContentView;
RemoteViews newHeadsUpContentView = mN.headsUpContentView;
if (newContentView == null) {
newContentView = createContentView();
mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
mN.contentView.getSequenceNumber());
newContentView.getSequenceNumber());
}
if (mN.bigContentView == null) {
mN.bigContentView = createBigContentView();
if (mN.bigContentView != null) {
if (newBigContentView == null) {
newBigContentView = createBigContentView();
if (newBigContentView != null) {
mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
mN.bigContentView.getSequenceNumber());
newBigContentView.getSequenceNumber());
}
}
if (mN.headsUpContentView == null) {
mN.headsUpContentView = createHeadsUpContentView();
if (mN.headsUpContentView != null) {
if (newHeadsUpContentView == null) {
newHeadsUpContentView = createHeadsUpContentView();
if (newHeadsUpContentView != null) {
mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
mN.headsUpContentView.getSequenceNumber());
newHeadsUpContentView.getSequenceNumber());
}
}
// Don't set any of the content views until after they have all been generated,
// to avoid the generated .contentView triggering the logic which skips generating
// the .bigContentView.
mN.contentView = newContentView;
mN.bigContentView = newBigContentView;
mN.headsUpContentView = newHeadsUpContentView;
}
if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
@ -12305,6 +12379,8 @@ public class Notification implements Parcelable
private int mSecondaryTextColor = COLOR_INVALID;
private int mPrimaryAccentColor = COLOR_INVALID;
private int mSecondaryAccentColor = COLOR_INVALID;
private int mTertiaryAccentColor = COLOR_INVALID;
private int mOnAccentTextColor = COLOR_INVALID;
private int mErrorColor = COLOR_INVALID;
private int mContrastColor = COLOR_INVALID;
private int mRippleAlpha = 0x33;
@ -12362,7 +12438,7 @@ public class Notification implements Parcelable
if (isColorized) {
if (rawColor == COLOR_DEFAULT) {
int[] attrs = {R.attr.colorAccentTertiary};
int[] attrs = {R.attr.colorAccentSecondary};
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
mBackgroundColor = getColor(ta, 0, Color.WHITE);
}
@ -12379,6 +12455,8 @@ public class Notification implements Parcelable
mContrastColor = mPrimaryTextColor;
mPrimaryAccentColor = mPrimaryTextColor;
mSecondaryAccentColor = mSecondaryTextColor;
mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
mOnAccentTextColor = mBackgroundColor;
mErrorColor = mPrimaryTextColor;
mRippleAlpha = 0x33;
} else {
@ -12389,6 +12467,8 @@ public class Notification implements Parcelable
R.attr.textColorSecondary,
R.attr.colorAccent,
R.attr.colorAccentSecondary,
R.attr.colorAccentTertiary,
R.attr.textColorOnAccent,
R.attr.colorError,
R.attr.colorControlHighlight
};
@ -12399,8 +12479,10 @@ public class Notification implements Parcelable
mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
mErrorColor = getColor(ta, 6, COLOR_INVALID);
mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
mErrorColor = getColor(ta, 8, COLOR_INVALID);
mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
}
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
mBackgroundColor, nightMode);
@ -12420,6 +12502,14 @@ public class Notification implements Parcelable
if (mSecondaryAccentColor == COLOR_INVALID) {
mSecondaryAccentColor = mContrastColor;
}
if (mTertiaryAccentColor == COLOR_INVALID) {
mTertiaryAccentColor = mContrastColor;
}
if (mOnAccentTextColor == COLOR_INVALID) {
mOnAccentTextColor = ColorUtils.setAlphaComponent(
ContrastColorUtil.resolvePrimaryColor(
ctx, mTertiaryAccentColor, nightMode), 0xFF);
}
if (mErrorColor == COLOR_INVALID) {
mErrorColor = mPrimaryTextColor;
}
@ -12485,6 +12575,16 @@ public class Notification implements Parcelable
return mSecondaryAccentColor;
}
/** @return the theme's tertiary accent color for colored UI elements. */
public @ColorInt int getTertiaryAccentColor() {
return mTertiaryAccentColor;
}
/** @return the theme's text color to be used on the tertiary accent color. */
public @ColorInt int getOnAccentTextColor() {
return mOnAccentTextColor;
}
/**
* @return the contrast-adjusted version of the color provided by the app, or the
* primary text color when colorized.

View File

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

View File

@ -559,6 +559,53 @@ public class WallpaperManager {
return null;
}
public Rect peekWallpaperDimensions(Context context, boolean returnDefault, int userId) {
if (mService != null) {
try {
if (!mService.isWallpaperSupported(context.getOpPackageName())) {
return new Rect();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Rect dimensions = null;
synchronized (this) {
try {
Bundle params = new Bundle();
// Let's peek user wallpaper first.
ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
context.getOpPackageName(), context.getAttributionTag(), this,
FLAG_SYSTEM, params, userId);
if (pfd != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, options);
dimensions = new Rect(0, 0, options.outWidth, options.outHeight);
}
} catch (RemoteException ex) {
Log.w(TAG, "peek wallpaper dimensions failed", ex);
}
}
// If user wallpaper is unavailable, may be the default one instead.
if ((dimensions == null || dimensions.width() == 0 || dimensions.height() == 0)
&& returnDefault) {
InputStream is = openDefaultWallpaper(context, FLAG_SYSTEM);
if (is != null) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
dimensions = new Rect(0, 0, options.outWidth, options.outHeight);
} finally {
IoUtils.closeQuietly(is);
}
}
}
return dimensions;
}
void forgetLoadedWallpaper() {
synchronized (this) {
mCachedWallpaper = null;
@ -1038,6 +1085,17 @@ public class WallpaperManager {
return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy);
}
/**
* Peek the dimensions of system wallpaper of the user without decoding it.
*
* @return the dimensions of system wallpaper
* @hide
*/
public Rect peekBitmapDimensions() {
return sGlobals.peekWallpaperDimensions(
mContext, true /* returnDefault */, mContext.getUserId());
}
/**
* Get an open, readable file descriptor to the given wallpaper image file.
* The caller is responsible for closing the file descriptor when done ingesting the file.

View File

@ -9733,6 +9733,27 @@ public class DevicePolicyManager {
return null;
}
/**
* @param userId The user for whom to retrieve information.
* @param restriction The restriction enforced by admin. It could be any user restriction or
* policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and
* {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}.
* @return Details of admin and user which enforced the restriction for the userId. If
* restriction is null, profile owner for the user or device owner info is returned.
* @hide
*/
public @Nullable Bundle getEnforcingAdminAndUserDetails(int userId,
@Nullable String restriction) {
if (mService != null) {
try {
return mService.getEnforcingAdminAndUserDetails(userId, restriction);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return null;
}
/**
* Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and
* actual package file remain. This function can be called by a device owner, profile owner, or

View File

@ -251,6 +251,7 @@ interface IDevicePolicyManager {
boolean isNotificationListenerServicePermitted(in String packageName, int userId);
Intent createAdminSupportIntent(in String restriction);
Bundle getEnforcingAdminAndUserDetails(int userId,String restriction);
boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent);
boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent);

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
* P and later, this method is a no-op.

View File

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

View File

@ -143,7 +143,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public ComponentName provider;
/**
* The default height of the widget when added to a host, in dp. The widget will get
* The default height of the widget when added to a host, in px. The widget will get
* at least this width, and will often be given more, depending on the host.
*
* <p>This field corresponds to the <code>android:minWidth</code> attribute in
@ -152,7 +152,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minWidth;
/**
* The default height of the widget when added to a host, in dp. The widget will get
* The default height of the widget when added to a host, in px. The widget will get
* at least this height, and will often be given more, depending on the host.
*
* <p>This field corresponds to the <code>android:minHeight</code> attribute in
@ -161,7 +161,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minHeight;
/**
* Minimum width (in dp) which the widget can be resized to. This field has no effect if it
* Minimum width (in px) which the widget can be resized to. This field has no effect if it
* is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
*
* <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
@ -170,7 +170,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minResizeWidth;
/**
* Minimum height (in dp) which the widget can be resized to. This field has no effect if it
* Minimum height (in px) which the widget can be resized to. This field has no effect if it
* is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
*
* <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
@ -179,7 +179,7 @@ public class AppWidgetProviderInfo implements Parcelable {
public int minResizeHeight;
/**
* Maximum width (in dp) which the widget can be resized to. This field has no effect if it is
* Maximum width (in px) which the widget can be resized to. This field has no effect if it is
* smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
*
* <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;
/**
* 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}).
*
* <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}
* or higher are not allowed to start background services from the background.
* See
* <a href="{@docRoot}/about/versions/oreo/background">
* <a href="/about/versions/oreo/background">
* Background Execution Limits</a>
* for more details.
*
@ -3295,7 +3295,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background.
* See
* <a href="{@docRoot}/about/versions/12/behavior-changes-12">
* <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12
* </a>
* for more details.
@ -3349,7 +3349,7 @@ public abstract class Context {
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background.
* See
* <a href="{@docRoot}/about/versions/12/behavior-changes-12">
* <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12
* </a>
* for more details.
@ -6026,6 +6026,10 @@ public abstract class Context {
* more general access to the URI's content provider then this check will
* always fail.
*
* <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 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

View File

@ -2742,6 +2742,22 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
/**
* Broadcast Action: One of the suspend conditions have been modified for the packages.
* <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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
# Camera
per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com
per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com
# Sensor Privacy
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -873,7 +873,6 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override
public int submitBurst(List<Request> requests, IRequestCallback callback) {
int seqId = -1;
synchronized (mInterfaceLock) {
try {
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
@ -888,7 +887,6 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
} catch (IllegalStateException e) {
Log.e(TAG, "Capture session closed!");
}
}
return seqId;
}
@ -896,7 +894,6 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override
public int setRepeating(Request request, IRequestCallback callback) {
int seqId = -1;
synchronized (mInterfaceLock) {
try {
CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
request, mCameraConfigMap);
@ -908,14 +905,12 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
} catch (IllegalStateException e) {
Log.e(TAG, "Capture session closed!");
}
}
return seqId;
}
@Override
public void abortCaptures() {
synchronized (mInterfaceLock) {
try {
mCaptureSession.abortCaptures();
} catch (CameraAccessException e) {
@ -924,11 +919,9 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
Log.e(TAG, "Capture session closed!");
}
}
}
@Override
public void stopRepeating() {
synchronized (mInterfaceLock) {
try {
mCaptureSession.stopRepeating();
} catch (CameraAccessException e) {
@ -938,7 +931,6 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
}
}
}
}
private static CaptureRequest initializeCaptureRequest(CameraDevice cameraDevice,
Request request, HashMap<Surface, CameraOutputConfig> surfaceIdMap)

View File

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

View File

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

View File

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

View File

@ -1257,6 +1257,23 @@ public final class DisplayManager {
*/
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
"fixed_refresh_rate_high_ambient_brightness_thresholds";
/**
* Key for refresh rate when the device is in high brightness mode for sunlight visility.
*
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
* @see android.R.integer#config_defaultRefreshRateInHbmSunlight
*/
String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight";
/**
* Key for refresh rate when the device is in high brightness mode for HDR.
*
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
* @see android.R.integer#config_defaultRefreshRateInHbmHdr
*/
String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr";
/**
* Key for default peak refresh rate
*

View File

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

View File

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

View File

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

View File

@ -146,6 +146,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private CryptoObject mCryptoObject;
@Nullable private RemoveTracker mRemoveTracker;
private Handler mHandler;
@Nullable private float[] mEnrollStageThresholds;
/**
* Retrieves a list of properties for all fingerprint sensors on the device.
@ -189,22 +190,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
private class OnAuthenticationCancelListener implements OnCancelListener {
private android.hardware.biometrics.CryptoObject mCrypto;
private final long mAuthRequestId;
public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
mCrypto = crypto;
OnAuthenticationCancelListener(long id) {
mAuthRequestId = id;
}
@Override
public void onCancel() {
cancelAuthentication(mCrypto);
Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
cancelAuthentication(mAuthRequestId);
}
}
private class OnFingerprintDetectionCancelListener implements OnCancelListener {
private final long mAuthRequestId;
OnFingerprintDetectionCancelListener(long id) {
mAuthRequestId = id;
}
@Override
public void onCancel() {
cancelFingerprintDetect();
Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId);
cancelFingerprintDetect(mAuthRequestId);
}
}
@ -552,13 +561,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
throw new IllegalArgumentException("Must supply an authentication callback");
}
if (cancel != null) {
if (cancel.isCanceled()) {
if (cancel != null && cancel.isCanceled()) {
Slog.w(TAG, "authentication already canceled");
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
}
}
if (mService != null) {
@ -567,8 +572,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mAuthenticationCallback = callback;
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver,
mContext.getOpPackageName());
final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
mServiceReceiver, mContext.getOpPackageName());
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try
@ -595,15 +603,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled");
return;
} else {
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
}
mFingerprintDetectionCallback = callback;
try {
mService.detectFingerprint(mToken, userId, mServiceReceiver,
final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
mContext.getOpPackageName());
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e);
}
@ -843,26 +850,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return hasEnrolledFingerprints(userId);
}
/**
* Checks if the specified user has enrollments in any of the specified sensors.
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledTemplatesForAnySensor(int userId,
@NonNull List<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
*/
@ -1320,26 +1307,66 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) {
private void cancelAuthentication(long requestId) {
if (mService != null) try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private void cancelFingerprintDetect() {
private void cancelFingerprintDetect(long requestId) {
if (mService == null) {
return;
}
try {
mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName());
mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
*/
public int getEnrollStageCount() {
if (mEnrollStageThresholds == null) {
mEnrollStageThresholds = createEnrollStageThresholds(mContext);
}
return mEnrollStageThresholds.length + 1;
}
/**
* @hide
*/
public float getEnrollStageThreshold(int index) {
if (mEnrollStageThresholds == null) {
mEnrollStageThresholds = createEnrollStageThresholds(mContext);
}
if (index < 0 || index > mEnrollStageThresholds.length) {
Slog.w(TAG, "Unsupported enroll stage index: " + index);
return index < 0 ? 0f : 1f;
}
// The implicit threshold for the final stage is always 1.
return index == mEnrollStageThresholds.length ? 1f : mEnrollStageThresholds[index];
}
@NonNull
private static float[] createEnrollStageThresholds(@NonNull Context context) {
// TODO(b/200604947): Fetch this value from FingerprintService, rather than internal config
final String[] enrollStageThresholdStrings = context.getResources().getStringArray(
com.android.internal.R.array.config_udfps_enroll_stage_thresholds);
final float[] enrollStageThresholds = new float[enrollStageThresholdStrings.length];
for (int i = 0; i < enrollStageThresholds.length; i++) {
enrollStageThresholds[i] = Float.parseFloat(enrollStageThresholdStrings[i]);
}
return enrollStageThresholds;
}
/**
* @hide
*/
@ -1390,9 +1417,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
// This is used as a last resort in case a vendor string is missing
// It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but
// warn and use the default if all else fails.
// TODO(b/196639965): update string
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
return "";
return context.getString(
com.android.internal.R.string.fingerprint_error_vendor_unknown);
}
/**

View File

@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener
* Defines behavior in response to state update
* @param newState new state of fingerprint sensor
*/
public abstract void onStateChanged(@FingerprintStateListener.State int newState);
public void onStateChanged(@FingerprintStateListener.State int newState) {};
/**
* Invoked when enrollment state changes for the specified user
*/
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {};
}

View File

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

View File

@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint;
*/
oneway interface IFingerprintStateListener {
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) {
return false;
}
if ((mInputEditorInfo != null
&& (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0)
if (mInputEditorInfo != null
&& ((mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0
// If app window has portrait orientation, regardless of what display orientation
// is, IME shouldn't use fullscreen-mode.
|| (mInputEditorInfo.internalImeOptions
& EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) {
& EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0)) {
return false;
}
return true;

View File

@ -270,6 +270,16 @@ public final class BatteryUsageStats implements Parcelable {
return mUserBatteryConsumers;
}
/**
* Returns the names of custom power components in order, so the first name in the array
* corresponds to the custom componentId
* {@link BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID}.
*/
@NonNull
public String[] getCustomPowerComponentNames() {
return mCustomPowerComponentNames;
}
/**
* Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
*/

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

View File

@ -17,6 +17,7 @@
package android.os;
import android.app.Activity;
import android.app.GameManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@ -26,8 +27,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@ -37,9 +36,6 @@ import dalvik.system.VMRuntime;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
@ -88,9 +84,6 @@ public class GraphicsEnvironment {
private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*";
private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
// ANGLE related properties.
private static final String ANGLE_RULES_FILE = "a4a_rules.json";
private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
@ -121,6 +114,7 @@ public class GraphicsEnvironment {
private ClassLoader mClassLoader;
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
private GameManager mGameManager;
private int mAngleOptInIndex = -1;
@ -133,6 +127,8 @@ public class GraphicsEnvironment {
final ApplicationInfo appInfoWithMetaData =
getAppInfoWithMetadata(context, pm, packageName);
mGameManager = context.getSystemService(GameManager.class);
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@ -150,6 +146,23 @@ public class GraphicsEnvironment {
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
/**
* Query to determine if the Game Mode has enabled ANGLE.
*/
private boolean isAngleEnabledByGameMode(Context context, String packageName) {
try {
final boolean gameModeEnabledAngle =
(mGameManager != null) && mGameManager.isAngleEnabled(packageName);
Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
return gameModeEnabledAngle;
} catch (SecurityException e) {
Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled "
+ "for package: " + packageName);
}
return false;
}
/**
* Query to determine if ANGLE should be used
*/
@ -164,21 +177,16 @@ public class GraphicsEnvironment {
Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
+ "set to: '" + devOptIn + "'");
// We only want to use ANGLE if the app is in the allowlist, or the developer has
// explicitly chosen something other than default driver.
// The allowlist will be generated by the ANGLE APK at both boot time and
// ANGLE update time. It will only include apps mentioned in the rules file.
final boolean allowed = checkAngleAllowlist(context, coreSettings, packageName);
// We only want to use ANGLE if the developer has explicitly chosen something other than
// default driver.
final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
if (allowed) {
Log.v(TAG, "ANGLE allowlist includes " + packageName);
}
if (requested) {
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
}
return allowed || requested;
final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
return requested || gameModeEnabledAngle;
}
private int getVulkanVersion(PackageManager pm) {
@ -474,117 +482,6 @@ public class GraphicsEnvironment {
return debugPackage;
}
/**
* Attempt to setup ANGLE with a temporary rules file.
* True: Temporary rules file was loaded.
* False: Temporary rules file was *not* loaded.
*/
private boolean setupAngleWithTempRulesFile(Context context,
String packageName,
String paths,
String devOptIn) {
/**
* We only want to load a temp rules file for:
* - apps that are marked 'debuggable' in their manifest
* - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
* debugging (PR_SET_DUMPABLE).
*/
if (!isDebuggable()) {
Log.v(TAG, "Skipping loading temporary rules file");
return false;
}
final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
if (TextUtils.isEmpty(angleTempRules)) {
Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
return false;
}
Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
final File tempRulesFile = new File(angleTempRules);
if (tempRulesFile.exists()) {
Log.i(TAG, angleTempRules + " exists, loading file.");
try {
final FileInputStream stream = new FileInputStream(angleTempRules);
try {
final FileDescriptor rulesFd = stream.getFD();
final long rulesOffset = 0;
final long rulesLength = stream.getChannel().size();
Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
setAngleInfo(paths, packageName, devOptIn, null,
rulesFd, rulesOffset, rulesLength);
stream.close();
// We successfully setup ANGLE, so return with good status
return true;
} catch (IOException e) {
Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
}
} catch (FileNotFoundException e) {
Log.w(TAG, "Temp ANGLE rules file not found: " + e);
} catch (SecurityException e) {
Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
}
}
return false;
}
/**
* Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
* True: APK rules file was loaded.
* False: APK rules file was *not* loaded.
*/
private boolean setupAngleRulesApk(String anglePkgName,
ApplicationInfo angleInfo,
PackageManager pm,
String packageName,
String paths,
String devOptIn,
String[] features) {
// Pass the rules file to loader for ANGLE decisions
try {
final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
try {
final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
setAngleInfo(paths, packageName, devOptIn, features, assetsFd.getFileDescriptor(),
assetsFd.getStartOffset(), assetsFd.getLength());
assetsFd.close();
return true;
} catch (IOException e) {
Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
+ " from '" + anglePkgName + "': " + e);
}
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
}
return false;
}
/**
* Pull ANGLE allowlist from GlobalSettings and compare against current package
*/
private boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
final ContentResolver contentResolver = context.getContentResolver();
final List<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
*
@ -647,30 +544,23 @@ public class GraphicsEnvironment {
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
// If the user has set the developer option to something other than default,
// we need to call setupAngleRulesApk() with the package name and the developer
// option value (native/angle/other). Then later when we are actually trying to
// load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before
// and can confidently answer yes/no based on the previously set developer
// option value.
final String devOptIn = getDriverForPackage(context, bundle, packageName);
if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
// We setup ANGLE with a temp rules file, so we're done here.
return true;
// We need to call setAngleInfo() with the package name and the developer option value
//(native/angle/other). Then later when we are actually trying to load a driver,
//GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
//answer yes/no based on the previously set developer option value.
final String devOptIn;
final String[] features = getAngleEglFeatures(context, bundle);
final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
if (gameModeEnabledAngle) {
devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
} else {
devOptIn = getDriverForPackage(context, bundle, packageName);
}
setAngleInfo(paths, packageName, devOptIn, features);
String[] features = getAngleEglFeatures(context, bundle);
if (setupAngleRulesApk(
anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
// ANGLE with rules is set up from the APK, hence return.
return true;
}
return false;
}
/**
* Determine if the "ANGLE In Use" dialog box should be shown.
*/
@ -956,7 +846,7 @@ public class GraphicsEnvironment {
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength);
String[] features);
private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();

View File

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

View File

@ -18,6 +18,7 @@ package android.os.storage;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.IVold;
import java.util.List;
@ -135,4 +136,19 @@ public abstract class StorageManagerInternal {
* {@link VolumeInfo#isPrimary()}
*/
public abstract List<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)
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.
* Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}.
@ -11844,6 +11859,12 @@ public final class Settings {
@Readable
public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed";
/**
* Whether UWB should be enabled.
* @hide
*/
public static final String UWB_ENABLED = "uwb_enabled";
/**
* Value to specify whether network quality scores and badging should be shown in the UI.
*
@ -13669,13 +13690,6 @@ public final class Settings {
public static final String ANGLE_GL_DRIVER_SELECTION_VALUES =
"angle_gl_driver_selection_values";
/**
* List of package names that should check ANGLE rules
* @hide
*/
@Readable
public static final String ANGLE_ALLOWLIST = "angle_allowlist";
/**
* Lists of ANGLE EGL features for debugging.
* Each list of features is separated by a comma, each feature in each list is separated by
@ -14914,6 +14928,16 @@ public final class Settings {
public static final String POWER_BUTTON_LONG_PRESS =
"power_button_long_press";
/**
* Override internal R.integer.config_longPressOnPowerDurationMs. It determines the length
* of power button press to be considered a long press in milliseconds.
* Used by PhoneWindowManager.
* @hide
*/
@Readable
public static final String POWER_BUTTON_LONG_PRESS_DURATION_MS =
"power_button_long_press_duration_ms";
/**
* Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
* Allowable values detailed in frameworks/base/core/res/res/values/config.xml.

View File

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

View File

@ -24,7 +24,7 @@ import com.android.internal.os.IResultReceiver;
/**
* 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
* enabled.
*

View File

@ -48,6 +48,7 @@ import android.view.translation.TranslationManager;
import android.view.translation.TranslationRequest;
import android.view.translation.TranslationResponse;
import android.view.translation.TranslationSpec;
import android.view.translation.Translator;
import com.android.internal.os.IResultReceiver;
@ -81,7 +82,10 @@ public abstract class TranslationService extends Service {
* android.R.styleable#TranslationService translation-service}&gt;</code> tag.
*
* <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";
@ -148,7 +152,6 @@ public abstract class TranslationService extends Service {
void onTranslationSuccess(@NonNull TranslationResponse response);
/**
* TODO: implement javadoc
* @removed use {@link #onTranslationSuccess} with an error response instead.
*/
@Deprecated
@ -225,7 +228,7 @@ public abstract class TranslationService extends Service {
* should call back with {@code false}.</p>
*
* @param translationContext the {@link TranslationContext} of the session being created.
* @param sessionId the int id of the session.
* @param sessionId the id of the session.
* @param callback {@link Consumer} to notify whether the session was successfully created.
*/
// TODO(b/176464808): the session id won't be unique cross client/server process. Need to find
@ -234,8 +237,6 @@ public abstract class TranslationService extends Service {
int sessionId, @NonNull Consumer<Boolean> callback);
/**
* TODO: fill in javadoc.
*
* @removed use {@link #onCreateTranslationSession(TranslationContext, int, Consumer)}
* instead.
*/
@ -246,19 +247,16 @@ public abstract class TranslationService extends Service {
}
/**
* TODO: fill in javadoc.
* Called when a translation session is finished.
*
* @param sessionId
* <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);
/**
* TODO: fill in javadoc.
*
* @param request
* @param sessionId
* @param callback
* @param cancellationSignal
* @removed use
* {@link #onTranslationRequest(TranslationRequest, int, CancellationSignal, Consumer)} instead.
*/
@ -276,23 +274,29 @@ public abstract class TranslationService extends Service {
* {@link TranslationRequest#FLAG_PARTIAL_RESPONSES} was set, the service may call
* {@code callback.accept()} multiple times with partial responses.</p>
*
* @param request
* @param sessionId
* @param callback
* @param cancellationSignal
* @param request The translation request containing the data to be translated.
* @param sessionId id of the session that sent the translation request.
* @param cancellationSignal A {@link CancellationSignal} that notifies when a client has
* cancelled the operation in progress.
* @param callback {@link Consumer} to pass back the translation response.
*/
public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
@Nullable CancellationSignal cancellationSignal,
@NonNull Consumer<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>
*
* @param sourceFormat
* @param targetFormat
* @param callback
* @param sourceFormat data format restriction of the translation source spec.
* @param targetFormat data format restriction of the translation target spec.
* @param callback {@link Consumer} to pass back the set of translation capabilities.
*/
public abstract void onTranslationCapabilitiesRequest(
@TranslationSpec.DataFormat int sourceFormat,

View File

@ -96,6 +96,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@ -152,6 +153,7 @@ public abstract class WallpaperService extends Service {
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
private static final int MSG_ZOOM = 10100;
private static final int MSG_SCALE_PREVIEW = 10110;
private static final int MSG_REPORT_SHOWN = 10150;
private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
Float.NEGATIVE_INFINITY);
@ -526,6 +528,39 @@ public abstract class WallpaperService extends Service {
return false;
}
/**
* This will be called in the end of {@link #updateSurface(boolean, boolean, boolean)}.
* If true is returned, the engine will not report shown until rendering finished is
* reported. Otherwise, the engine will report shown immediately right after redraw phase
* in {@link #updateSurface(boolean, boolean, boolean)}.
*
* @hide
*/
public boolean shouldWaitForEngineShown() {
return false;
}
/**
* Reports the rendering is finished, stops waiting, then invokes
* {@link IWallpaperEngineWrapper#reportShown()}.
*
* @hide
*/
public void reportEngineShown(boolean waitForEngineShown) {
if (mIWallpaperEngine.mShownReported) return;
if (!waitForEngineShown) {
Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
mCaller.removeMessages(MSG_REPORT_SHOWN);
mCaller.sendMessage(message);
} else {
// if we are already waiting, no need to reset the timeout.
if (!mCaller.hasMessages(MSG_REPORT_SHOWN)) {
Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
mCaller.sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(5));
}
}
}
/**
* Control whether this wallpaper will receive raw touch events
* from the window manager as the user interacts with the window
@ -930,7 +965,7 @@ public abstract class WallpaperService extends Service {
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface: destroyed");
Log.w(TAG, "Ignoring updateSurface due to destroyed");
}
boolean fixedSize = false;
@ -1197,7 +1232,6 @@ public abstract class WallpaperService extends Service {
+ this);
onVisibilityChanged(false);
}
} finally {
mIsCreating = false;
mSurfaceCreated = true;
@ -1207,7 +1241,7 @@ public abstract class WallpaperService extends Service {
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
reposition();
mIWallpaperEngine.reportShown();
reportEngineShown(shouldWaitForEngineShown());
}
} catch (RemoteException ex) {
}
@ -2048,6 +2082,8 @@ public abstract class WallpaperService extends Service {
mShownReported = true;
try {
mConnection.engineShown(this);
Log.d(TAG, "Wallpaper has updated the surface:"
+ mWallpaperManager.getWallpaperInfo());
} catch (RemoteException e) {
Log.w(TAG, "Wallpaper host disappeared", e);
return;
@ -2201,6 +2237,9 @@ public abstract class WallpaperService extends Service {
// Connection went away, nothing to do in here.
}
} break;
case MSG_REPORT_SHOWN: {
reportShown();
} break;
default :
Log.w(TAG, "Unknown message type " + message.what);
}

View File

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

View File

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

View File

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

View File

@ -814,9 +814,10 @@ interface IWindowManager
* @param displayId The display associated with the window context
* @param options A bundle used to pass window-related options and choose the right DisplayArea
*
* @return {@code true} if the WindowContext is attached to the DisplayArea successfully.
* @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is
* attached to the DisplayArea successfully. {@code null}, otherwise.
*/
boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
in Bundle options);
/**

View File

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

View File

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

View File

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

View File

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

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

View File

@ -57,6 +57,9 @@ public class TranslateAnimation extends Animation {
/** @hide */
protected float mToYDelta;
private int mWidth;
private int mParentWidth;
/**
* Constructor used when a TranslateAnimation is loaded from a resource.
*
@ -179,5 +182,60 @@ public class TranslateAnimation extends Animation {
mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
mWidth = width;
mParentWidth = parentWidth;
}
/**
* Checks whether or not the translation is exclusively an x axis translation.
*
* @hide
*/
public boolean isXAxisTransition() {
return mFromXDelta - mToXDelta != 0 && mFromYDelta - mToYDelta == 0;
}
/**
* Checks whether or not the translation is a full width x axis slide in or out translation.
*
* @hide
*/
public boolean isFullWidthTranslate() {
boolean isXAxisSlideTransition =
isSlideInLeft() || isSlideOutRight() || isSlideInRight() || isSlideOutLeft();
return mWidth == mParentWidth && isXAxisSlideTransition;
}
private boolean isSlideInLeft() {
boolean startsOutOfParentOnLeft = mFromXDelta <= -mWidth;
return startsOutOfParentOnLeft && endsXEnclosedWithinParent();
}
private boolean isSlideOutRight() {
boolean endOutOfParentOnRight = mToXDelta >= mParentWidth;
return startsXEnclosedWithinParent() && endOutOfParentOnRight;
}
private boolean isSlideInRight() {
boolean startsOutOfParentOnRight = mFromXDelta >= mParentWidth;
return startsOutOfParentOnRight && endsXEnclosedWithinParent();
}
private boolean isSlideOutLeft() {
boolean endOutOfParentOnLeft = mToXDelta <= -mWidth;
return startsXEnclosedWithinParent() && endOutOfParentOnLeft;
}
private boolean endsXEnclosedWithinParent() {
return mWidth <= mParentWidth
&& mToXDelta + mWidth <= mParentWidth
&& mToXDelta >= 0;
}
private boolean startsXEnclosedWithinParent() {
return mWidth <= mParentWidth
&& mFromXDelta + mWidth <= mParentWidth
&& mFromXDelta >= 0;
}
}

View File

@ -40,15 +40,18 @@ import java.util.function.Consumer;
public final class TranslationCapability implements Parcelable {
/**
* TODO: fill in javadoc
* The translation service supports translation between the source and target specs, and it is
* ready to be downloaded onto the device.
*/
public static final @ModelState int STATE_AVAILABLE_TO_DOWNLOAD = 1;
/**
* TODO: fill in javadoc
* The translation service supports translation between the source and target specs, and it is
* being downloaded onto the device currently.
*/
public static final @ModelState int STATE_DOWNLOADING = 2;
/**
* TODO: fill in javadoc
* The translation service supports translation between the source and target specs, and it is
* downloaded and ready to use on device.
*/
public static final @ModelState int STATE_ON_DEVICE = 3;
/**
@ -305,7 +308,7 @@ public final class TranslationCapability implements Parcelable {
};
@DataClass.Generated(
time = 1624307114468L,
time = 1629158466039L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationCapability.java",
inputSignatures = "public static final @android.view.translation.TranslationCapability.ModelState int STATE_AVAILABLE_TO_DOWNLOAD\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_DOWNLOADING\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_ON_DEVICE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_NOT_AVAILABLE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_REMOVED_AND_AVAILABLE\nprivate final @android.view.translation.TranslationCapability.ModelState int mState\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mTargetSpec\nprivate final boolean mUiTranslationEnabled\nprivate final @android.view.translation.TranslationContext.TranslationFlag int mSupportedTranslationFlags\nclass TranslationCapability extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstDefs=true, genToString=true, genConstructor=false)")

View File

@ -39,12 +39,16 @@ public final class TranslationRequest implements Parcelable {
public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1;
/**
* Indicates this request wants to receive the dictionary result.
* TODO: describe the structure of the result.
*
* <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;
/**
* 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;
/**
@ -327,7 +331,8 @@ public final class TranslationRequest implements Parcelable {
return this;
}
/** @see #setTranslationRequestValues
/**
* @see #setTranslationRequestValues
* @removed
*/
@DataClass.Generated.Member
@ -352,7 +357,8 @@ public final class TranslationRequest implements Parcelable {
return this;
}
/** @see #setViewTranslationRequests
/**
* @see #setViewTranslationRequests
* @removed
*/
@DataClass.Generated.Member
@ -394,7 +400,7 @@ public final class TranslationRequest implements Parcelable {
}
@DataClass.Generated(
time = 1620429997487L,
time = 1629159107226L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java",
inputSignatures = "public static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_DICTIONARY_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLITERATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_PARTIAL_RESPONSES\nprivate final @android.view.translation.TranslationRequest.RequestFlags int mFlags\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.List<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
private final Bundle mExtras;
// TODO: Add example of transliteration.
/**
* 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
private final CharSequence mTransliteration;
@ -223,7 +225,8 @@ public final class TranslationResponseValue implements Parcelable {
/**
* The transliteration result of the translated text.
* TODO: Describe the result structure.
*
* <p>This returns a CharSequence representation of the transliteration of the translated text.
*/
@DataClass.Generated.Member
public @Nullable CharSequence getTransliteration() {
@ -407,7 +410,8 @@ public final class TranslationResponseValue implements Parcelable {
/**
* The transliteration result of the translated text.
* TODO: Describe the result structure.
*
* <p>This returns a CharSequence representation of the transliteration of the translated text.
*/
@DataClass.Generated.Member
public @NonNull Builder setTransliteration(@NonNull CharSequence value) {
@ -448,7 +452,7 @@ public final class TranslationResponseValue implements Parcelable {
}
@DataClass.Generated(
time = 1622133051937L,
time = 1631057245846L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java",
inputSignatures = "public static final int STATUS_SUCCESS\npublic static final int STATUS_ERROR\npublic static final java.lang.String EXTRA_DEFINITIONS\nprivate final @android.view.translation.TranslationResponseValue.Status int mStatusCode\nprivate final @android.annotation.Nullable java.lang.CharSequence mText\nprivate final @android.annotation.NonNull android.os.Bundle mExtras\nprivate final @android.annotation.Nullable java.lang.CharSequence mTransliteration\npublic static @android.annotation.NonNull android.view.translation.TranslationResponseValue forError()\nprivate static java.lang.CharSequence defaultText()\nprivate static android.os.Bundle defaultExtras()\nprivate boolean extrasEquals(android.os.Bundle)\nprivate static java.lang.CharSequence defaultTransliteration()\nclass TranslationResponseValue extends java.lang.Object implements [android.os.Parcelable]\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)\nclass BaseBuilder extends java.lang.Object implements []")

View File

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

View File

@ -33,6 +33,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.view.autofill.AutofillId;
import android.widget.TextView;
import com.android.internal.annotations.GuardedBy;
@ -42,11 +43,50 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
// TODO(b/178044703): Describe what UI Translation is.
/**
* The {@link UiTranslationManager} class provides ways for apps to use the ui translation
* <p>The {@link UiTranslationManager} class provides ways for apps to use the ui translation
* 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 {
@ -248,14 +288,14 @@ public final class UiTranslationManager {
}
}
// TODO(b/178044703): Fix the View API link when it becomes public.
/**
* Register for notifications of UI Translation state changes on the foreground activity. This
* is available to the owning application itself and also the current input method.
* <p>
* The application whose UI is being translated can use this to customize the UI Translation
* behavior in ways that aren't made easy by methods like
* View#onCreateTranslationRequest().
* {@link View#onCreateViewTranslationRequest(int[], Consumer)}.
*
* <p>
* 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

View File

@ -19,9 +19,17 @@ package android.view.translation;
import android.annotation.NonNull;
import android.annotation.UiThread;
import android.view.View;
import android.view.contentcapture.ContentCaptureSession;
/**
* Callback for handling the translated information show or hide in the {@link View}.
* <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
public interface ViewTranslationCallback {
@ -33,13 +41,24 @@ public interface ViewTranslationCallback {
* method will not be called before {@link View#onViewTranslationResponse} or
* {@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.
*
* @return {@code true} if the View handles showing the translation.
*/
boolean onShowTranslation(@NonNull View view);
/**
* Called when the user wants to show the original text instead of the translated text. This
* Called when user wants to view the original content instead of the translated content. This
* method will not be called before {@link View#onViewTranslationResponse} or
* {@link View#onViewTranslationResponse}.
*
@ -47,7 +66,8 @@ public interface ViewTranslationCallback {
*/
boolean onHideTranslation(@NonNull View view);
/**
* Called when the user finish the Ui translation and no longer to show the translated text.
* Called when the translation state is no longer needed. It should restore the original content
* and clear all saved states.
*
* @return {@code true} if the View handles clearing the translation.
*/

View File

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

View File

@ -64,13 +64,24 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
if (mIsShowingTranslation) {
if (DEBUG) {
Log.d(TAG, view + " is already showing translated text.");
}
return false;
}
ViewTranslationResponse response = view.getViewTranslationResponse();
if (response == null) {
Log.e(TAG, "onShowTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
return false;
}
if (mTranslationTransformation == null) {
// It is possible user changes text and new translation response returns, system should
// update the translation response to keep the result up to date.
// Because TextView.setTransformationMethod() will skip the same TransformationMethod
// instance, we should create a new one to let new translation can work.
if (mTranslationTransformation == null
|| !response.equals(mTranslationTransformation.getViewTranslationResponse())) {
TransformationMethod originalTranslationMethod =
((TextView) view).getTransformationMethod();
mTranslationTransformation = new TranslationTransformationMethod(response,
@ -147,7 +158,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
return true;
}
boolean isShowingTranslation() {
public boolean isShowingTranslation() {
return mIsShowingTranslation;
}

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

View File

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

View File

@ -19,6 +19,7 @@ package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@ -46,7 +47,7 @@ public class WindowContextController {
@VisibleForTesting
public boolean mAttachedToDisplayArea;
@NonNull
private final IBinder mToken;
private final WindowTokenClient mToken;
/**
* Window Context Controller constructor
@ -54,14 +55,13 @@ public class WindowContextController {
* @param token The token used to attach to a window manager node. It is usually from
* {@link Context#getWindowContextToken()}.
*/
public WindowContextController(@NonNull IBinder token) {
mToken = token;
mWms = WindowManagerGlobal.getWindowManagerService();
public WindowContextController(@NonNull WindowTokenClient token) {
this(token, WindowManagerGlobal.getWindowManagerService());
}
/** Used for test only. DO NOT USE it in production code. */
@VisibleForTesting
public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) {
public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
mToken = token;
mWms = mockWms;
}
@ -81,8 +81,14 @@ public class WindowContextController {
+ "a DisplayArea once.");
}
try {
mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId,
options);
final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
displayId, options);
if (configuration != null) {
mAttachedToDisplayArea = true;
// Send the DisplayArea's configuration to WindowContext directly instead of
// waiting for dispatching from WMS.
mToken.onConfigurationChanged(configuration, displayId);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

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

View File

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

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
Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
.getIconBitmap(android.os.Process.myUserHandle());
.getIconBitmap(mContext.getUser());
// Raster target drawable with appIcon as a badge
SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);

View File

@ -50,6 +50,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;
/**
* A class that allows the app to get the frame metrics from HardwareRendererObserver.
@ -103,6 +104,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
private boolean mCancelled = false;
private FrameTrackerListener mListener;
private boolean mTracingStarted = false;
private Runnable mWaitForFinishTimedOut;
private static class JankInfo {
long frameVsyncId;
@ -263,10 +265,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
if (mListener != null) {
mListener.onCujEvents(mSession, ACTION_SESSION_END);
}
}
// We don't remove observer here,
// will remove it when all the frame metrics in this duration are called back.
// See onFrameMetricsAvailable for the logic of removing the observer.
// Waiting at most 10 seconds for all callbacks to finish.
mWaitForFinishTimedOut = () -> {
Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
finish(mJankInfos.size() - 1);
};
mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
}
}
/**
@ -396,7 +404,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
private void finish(int indexOnOrAfterEnd) {
mHandler.removeCallbacks(mWaitForFinishTimedOut);
mWaitForFinishTimedOut = null;
mMetricsFinalized = true;
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
@ -481,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
if (DEBUG) {
Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
Log.i(TAG, "finish: CUJ=" + mSession.getName()
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
+ " totalFrames=" + totalFramesCount
+ " missedAppFrames=" + missedAppFramesCount

View File

@ -103,7 +103,7 @@ public class InteractionJankMonitor {
private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L);
private static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =

View File

@ -707,6 +707,10 @@ public class BatteryStatsImpl extends BatteryStats {
* Mapping isolated uids to the actual owning app uid.
*/
final SparseIntArray mIsolatedUids = new SparseIntArray();
/**
* Internal reference count of isolated uids.
*/
final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray();
/**
* The statistics we have collected organized by uids.
@ -3897,6 +3901,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void addIsolatedUidLocked(int isolatedUid, int appUid,
long elapsedRealtimeMs, long uptimeMs) {
mIsolatedUids.put(isolatedUid, appUid);
mIsolatedUidRefCounts.put(isolatedUid, 1);
final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
u.addIsolatedUid(isolatedUid);
}
@ -3915,19 +3920,51 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
* This should only be called after the cpu times have been read.
* Isolated uid should only be removed after all wakelocks associated with the uid are stopped
* and the cpu time-in-state has been read one last time for the uid.
*
* @see #scheduleRemoveIsolatedUidLocked(int, int)
*
* @return true if the isolated uid is actually removed.
*/
@GuardedBy("this")
public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs,
long uptimeMs) {
final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1;
if (refCount > 0) {
// Isolated uid is still being tracked
mIsolatedUidRefCounts.put(isolatedUid, refCount);
return false;
}
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
if (idx >= 0) {
final int ownerUid = mIsolatedUids.valueAt(idx);
final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
u.removeIsolatedUid(isolatedUid);
mIsolatedUids.removeAt(idx);
mIsolatedUidRefCounts.delete(isolatedUid);
} else {
Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")");
}
mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
return true;
}
/**
* Increment the ref count for an isolated uid.
* call #maybeRemoveIsolatedUidLocked to decrement.
*/
public void incrementIsolatedUidRefCount(int uid) {
final int refCount = mIsolatedUidRefCounts.get(uid, 0);
if (refCount <= 0) {
// Uid is not mapped or referenced
Slog.w(TAG,
"Attempted to increment ref counted of untracked isolated uid (" + uid + ")");
return;
}
mIsolatedUidRefCounts.put(uid, refCount + 1);
}
public int mapUid(int uid) {
@ -4287,7 +4324,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
uid = mapUid(uid);
final int mappedUid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep.
@ -4297,9 +4334,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (mRecordAllHistory) {
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
uid, 0)) {
mappedUid, 0)) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid);
}
}
if (mWakeLockNesting == 0) {
@ -4308,7 +4345,7 @@ public class BatteryStatsImpl extends BatteryStats {
+ Integer.toHexString(mHistoryCur.states));
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
} else if (!mWakeLockImportant && !unimportantForLogging
@ -4318,14 +4355,19 @@ public class BatteryStatsImpl extends BatteryStats {
mHistoryLastWritten.wakelockTag = null;
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
mWakeLockImportant = true;
}
mWakeLockNesting++;
}
if (uid >= 0) {
if (mappedUid >= 0) {
if (mappedUid != uid) {
// Prevent the isolated uid mapping from being removed while the wakelock is
// being held.
incrementIsolatedUidRefCount(uid);
}
if (mOnBatteryScreenOffTimeBase.isRunning()) {
// We only update the cpu time when a wake lock is acquired if the screen is off.
// If the screen is on, we don't distribute the power amongst partial wakelocks.
@ -4335,7 +4377,7 @@ public class BatteryStatsImpl extends BatteryStats {
requestWakelockCpuUpdate();
}
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
if (wc != null) {
@ -4343,8 +4385,8 @@ public class BatteryStatsImpl extends BatteryStats {
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
mappedUid, null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
}
}
@ -4358,7 +4400,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
int type, long elapsedRealtimeMs, long uptimeMs) {
uid = mapUid(uid);
final int mappedUid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
if (mRecordAllHistory) {
@ -4366,9 +4408,9 @@ public class BatteryStatsImpl extends BatteryStats {
historyName = name;
}
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
uid, 0)) {
mappedUid, 0)) {
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid);
}
}
if (mWakeLockNesting == 0) {
@ -4380,7 +4422,7 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
}
if (uid >= 0) {
if (mappedUid >= 0) {
if (mOnBatteryScreenOffTimeBase.isRunning()) {
if (DEBUG_ENERGY_CPU) {
Slog.d(TAG, "Updating cpu time because of -wake_lock");
@ -4388,17 +4430,22 @@ public class BatteryStatsImpl extends BatteryStats {
requestWakelockCpuUpdate();
}
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
if (wc != null) {
FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
mappedUid, null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
}
if (mappedUid != uid) {
// Decrement the ref count for the isolated uid and delete the mapping if uneeded.
maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs);
}
}
}
@ -8571,7 +8618,7 @@ public class BatteryStatsImpl extends BatteryStats {
* inactive so can be dropped.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public boolean reset(long uptimeUs, long realtimeUs) {
public boolean reset(long uptimeUs, long realtimeUs, int resetReason) {
boolean active = false;
mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs);
@ -8641,7 +8688,11 @@ public class BatteryStatsImpl extends BatteryStats {
resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs);
resetIfNotNull(mModemControllerActivity, false, realtimeUs);
if (resetReason == RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE) {
mUidMeasuredEnergyStats = null;
} else {
MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats);
}
resetIfNotNull(mUserCpuTime, false, realtimeUs);
resetIfNotNull(mSystemCpuTime, false, realtimeUs);
@ -11324,7 +11375,7 @@ public class BatteryStatsImpl extends BatteryStats {
mNumConnectivityChange = 0;
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs)) {
if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs, resetReason)) {
mUidStats.valueAt(i).detachFromTimeBase();
mUidStats.remove(mUidStats.keyAt(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.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();
dumpConstantsLocked(pw);

View File

@ -29,6 +29,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -234,8 +235,9 @@ public class BatteryUsageStatsProvider {
final boolean includePowerModels = (query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames();
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
mStats.getCustomEnergyConsumerNames(), includePowerModels);
customEnergyConsumerNames, includePowerModels);
if (mBatteryUsageStatsStore == null) {
Log.e(TAG, "BatteryUsageStatsStore is unavailable");
return builder.build();
@ -247,7 +249,14 @@ public class BatteryUsageStatsProvider {
final BatteryUsageStats snapshot =
mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
if (snapshot != null) {
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.BatteryUsageStatsQuery;
import android.os.UidBatteryConsumer;
import android.util.Slog;
import android.util.SparseArray;
import java.util.Arrays;
/**
* Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type
* {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
*/
public class CustomMeasuredPowerCalculator extends PowerCalculator {
private static final String TAG = "CustomMeasuredPowerCalc";
public CustomMeasuredPowerCalculator(PowerProfile powerProfile) {
}
@ -76,9 +81,9 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator {
if (totalPowerMah == null) {
newTotalPowerMah = new double[customMeasuredPowerMah.length];
} else if (totalPowerMah.length != customMeasuredPowerMah.length) {
newTotalPowerMah = new double[customMeasuredPowerMah.length];
System.arraycopy(totalPowerMah, 0, newTotalPowerMah, 0,
customMeasuredPowerMah.length);
Slog.wtf(TAG, "Number of custom energy components is not the same for all apps: "
+ totalPowerMah.length + ", " + customMeasuredPowerMah.length);
newTotalPowerMah = Arrays.copyOf(totalPowerMah, customMeasuredPowerMah.length);
} else {
newTotalPowerMah = totalPowerMah;
}

View File

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

View File

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

View File

@ -148,7 +148,7 @@ oneway interface IStatusBar
*/
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
String opPackageName, long operationId, int multiSensorConfig);
long operationId, String opPackageName, long requestId, int multiSensorConfig);
/**
* Used to notify the authentication dialog that a biometric has been authenticated.
*/

View File

@ -110,7 +110,8 @@ interface IStatusBarService
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId, int multiSensorConfig);
int userId, long operationId, String opPackageName, long requestId,
int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();

View File

@ -291,10 +291,10 @@ public class ContrastColorUtil {
* Finds a suitable color such that there's enough contrast.
*
* @param color the color to start searching from.
* @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
* @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
* @param other the color to ensure contrast against. Assumed to be lighter than {@code color}
* @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
* @param minRatio the minimum contrast ratio required.
* @return a color with the same hue as {@param color}, potentially darkened to meet the
* @return a color with the same hue as {@code color}, potentially darkened to meet the
* contrast ratio.
*/
public static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
@ -331,7 +331,7 @@ public class ContrastColorUtil {
* @param color the color to start searching from.
* @param backgroundColor the color to ensure contrast against.
* @param minRatio the minimum contrast ratio required.
* @return the same color as {@param color} with potentially modified alpha to meet contrast
* @return the same color as {@code color} with potentially modified alpha to meet contrast
*/
public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
int fg = color;
@ -361,10 +361,10 @@ public class ContrastColorUtil {
* Finds a suitable color such that there's enough contrast.
*
* @param color the color to start searching from.
* @param other the color to ensure contrast against. Assumed to be darker than {@param color}
* @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
* @param other the color to ensure contrast against. Assumed to be darker than {@code color}
* @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
* @param minRatio the minimum contrast ratio required.
* @return a color with the same hue as {@param color}, potentially darkened to meet the
* @return a color with the same hue as {@code color}, potentially lightened to meet the
* contrast ratio.
*/
public static int findContrastColorAgainstDark(int color, int other, boolean findFg,
@ -393,7 +393,8 @@ public class ContrastColorUtil {
low = l;
}
}
return findFg ? fg : bg;
hsl[2] = high;
return ColorUtilsFromCompat.HSLToColor(hsl);
}
public static int ensureTextContrastOnBlack(int color) {
@ -452,7 +453,7 @@ public class ContrastColorUtil {
}
/**
* Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
* Resolves {@code color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
*/
public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
if (color == Notification.COLOR_DEFAULT) {

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 Protocol* = etancohen@google.com, lorenzo@google.com
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file DataClass* = eugenesusla@google.com

View File

@ -17,6 +17,7 @@
package com.android.internal.widget;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
@ -1271,6 +1272,14 @@ public class LockPatternUtils {
}
}
/**
* Whether the user is not allowed to set any credentials via PASSWORD_QUALITY_MANAGED.
*/
public boolean isCredentialsDisabledForUser(int userId) {
return getDevicePolicyManager().getPasswordQuality(/* admin= */ null, userId)
== PASSWORD_QUALITY_MANAGED;
}
/**
* @see StrongAuthTracker#isTrustAllowedForUser
*/

View File

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

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