Merge sc-qpr1-dev-plus-aosp-without-vendor@7810918
Bug: 205056467 Merged-In: I13199bc39e9445929195f3d15579cbffe94e92b0 Change-Id: I35fa3c6c2abf679c51033f1395a08d511ed8739f
This commit is contained in:
commit
10d9972786
@ -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,
|
||||
|
@ -71,7 +71,7 @@ cc_library_shared {
|
||||
"libui",
|
||||
"libjnigraphics",
|
||||
"libEGL",
|
||||
"libGLESv1_CM",
|
||||
"libGLESv2",
|
||||
"libgui",
|
||||
],
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
glGenTextures(1, &frame.tid);
|
||||
glBindTexture(GL_TEXTURE_2D, frame.tid);
|
||||
int w, h;
|
||||
initTexture(frame.map, &w, &h);
|
||||
// Set decoding option to alpha unpremultiplied so that the R, G, B channels
|
||||
// of transparent pixels are preserved.
|
||||
initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
|
||||
}
|
||||
|
||||
const int xc = animationX + frame.trimX;
|
||||
const int yc = animationY + frame.trimY;
|
||||
Region clearReg(Rect(mWidth, mHeight));
|
||||
clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
|
||||
if (!clearReg.isEmpty()) {
|
||||
Region::const_iterator head(clearReg.begin());
|
||||
Region::const_iterator tail(clearReg.end());
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
while (head != tail) {
|
||||
const Rect& r2(*head++);
|
||||
glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
|
||||
// which is equivalent to mHeight - (yc + frame.trimHeight)
|
||||
const int frameDrawY = mHeight - (yc + frame.trimHeight);
|
||||
glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
|
||||
|
||||
float fade = 0;
|
||||
// if the part hasn't been stopped yet then continue fading if necessary
|
||||
if (exitPending() && part.hasFadingPhase()) {
|
||||
fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
|
||||
++fadedFramesCount);
|
||||
fade = static_cast<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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -1,4 +1,3 @@
|
||||
set noparent
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
zyy@google.com
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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 {
|
||||
int notifBackgroundColor = getColors(p).getBackgroundColor();
|
||||
title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor);
|
||||
// Check for a full-length span color to use as the button fill color.
|
||||
Integer fullLengthColor = getFullLengthSpanColor(title);
|
||||
if (fullLengthColor != null) {
|
||||
// Ensure the custom button fill has 1.3:1 contrast w/ notification bg.
|
||||
int notifBackgroundColor = getColors(p).getBackgroundColor();
|
||||
buttonFillColor = ensureButtonFillContrast(
|
||||
fullLengthColor, notifBackgroundColor);
|
||||
}
|
||||
// Remove full-length color spans and ensure text contrast with the button fill.
|
||||
title = ensureColorSpanContrast(title, buttonFillColor);
|
||||
}
|
||||
button.setTextViewText(R.id.action0, processTextSpans(title));
|
||||
boolean hasColorOverride = outResultColor[0] != null;
|
||||
if (hasColorOverride) {
|
||||
// There's a span spanning the full text, let's take it and use it as the
|
||||
// background color
|
||||
buttonFillColor = outResultColor[0].getDefaultColor();
|
||||
}
|
||||
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
|
||||
buttonFillColor, mInNightMode);
|
||||
button.setTextColor(R.id.action0, textColor);
|
||||
@ -6168,17 +6177,58 @@ public class Notification implements Parcelable
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures contrast on color spans against a background color. also returns the color of the
|
||||
* text if a span was found that spans over the whole text.
|
||||
* Extract the color from a full-length span from the text.
|
||||
*
|
||||
* @param charSequence the charSequence containing spans
|
||||
* @return the raw color of the text's last full-length span containing a color, or null if
|
||||
* no full-length span sets the text color.
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public static Integer getFullLengthSpanColor(CharSequence charSequence) {
|
||||
// NOTE: this method preserves the functionality that for a CharSequence with multiple
|
||||
// full-length spans, the color of the last one is used.
|
||||
Integer result = null;
|
||||
if (charSequence instanceof Spanned) {
|
||||
Spanned ss = (Spanned) charSequence;
|
||||
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
|
||||
// First read through all full-length spans to get the button fill color, which will
|
||||
// be used as the background color for ensuring contrast of non-full-length spans.
|
||||
for (Object span : spans) {
|
||||
int spanStart = ss.getSpanStart(span);
|
||||
int spanEnd = ss.getSpanEnd(span);
|
||||
boolean fullLength = (spanEnd - spanStart) == charSequence.length();
|
||||
if (!fullLength) {
|
||||
continue;
|
||||
}
|
||||
if (span instanceof TextAppearanceSpan) {
|
||||
TextAppearanceSpan originalSpan = (TextAppearanceSpan) span;
|
||||
ColorStateList textColor = originalSpan.getTextColor();
|
||||
if (textColor != null) {
|
||||
result = textColor.getDefaultColor();
|
||||
}
|
||||
} else if (span instanceof ForegroundColorSpan) {
|
||||
ForegroundColorSpan originalSpan = (ForegroundColorSpan) span;
|
||||
result = originalSpan.getForegroundColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures contrast on color spans against a background color.
|
||||
* Note that any full-length color spans will be removed instead of being contrasted.
|
||||
*
|
||||
* @param charSequence the charSequence on which the spans are
|
||||
* @param background the background color to ensure the contrast against
|
||||
* @param outResultColor an array in which a color will be returned as the first element if
|
||||
* there exists a full length color span.
|
||||
* @return the contrasted charSequence
|
||||
* @hide
|
||||
*/
|
||||
private static CharSequence ensureColorSpanContrast(CharSequence charSequence,
|
||||
int background, ColorStateList[] outResultColor) {
|
||||
@VisibleForTesting
|
||||
public static CharSequence ensureColorSpanContrast(CharSequence charSequence,
|
||||
int background) {
|
||||
if (charSequence instanceof Spanned) {
|
||||
Spanned ss = (Spanned) charSequence;
|
||||
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
|
||||
@ -6195,19 +6245,19 @@ public class Notification implements Parcelable
|
||||
TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
|
||||
ColorStateList textColor = originalSpan.getTextColor();
|
||||
if (textColor != null) {
|
||||
int[] colors = textColor.getColors();
|
||||
int[] newColors = new int[colors.length];
|
||||
for (int i = 0; i < newColors.length; i++) {
|
||||
boolean isBgDark = isColorDark(background);
|
||||
newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
|
||||
colors[i], background, isBgDark);
|
||||
}
|
||||
textColor = new ColorStateList(textColor.getStates().clone(),
|
||||
newColors);
|
||||
if (fullLength) {
|
||||
outResultColor[0] = textColor;
|
||||
// Let's drop the color from the span
|
||||
textColor = null;
|
||||
} else {
|
||||
int[] colors = textColor.getColors();
|
||||
int[] newColors = new int[colors.length];
|
||||
for (int i = 0; i < newColors.length; i++) {
|
||||
boolean isBgDark = isColorDark(background);
|
||||
newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
|
||||
colors[i], background, isBgDark);
|
||||
}
|
||||
textColor = new ColorStateList(textColor.getStates().clone(),
|
||||
newColors);
|
||||
}
|
||||
resultSpan = new TextAppearanceSpan(
|
||||
originalSpan.getFamily(),
|
||||
@ -6217,15 +6267,14 @@ public class Notification implements Parcelable
|
||||
originalSpan.getLinkTextColor());
|
||||
}
|
||||
} else if (resultSpan instanceof ForegroundColorSpan) {
|
||||
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
|
||||
int foregroundColor = originalSpan.getForegroundColor();
|
||||
boolean isBgDark = isColorDark(background);
|
||||
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
|
||||
foregroundColor, background, isBgDark);
|
||||
if (fullLength) {
|
||||
outResultColor[0] = ColorStateList.valueOf(foregroundColor);
|
||||
resultSpan = null;
|
||||
} else {
|
||||
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
|
||||
int foregroundColor = originalSpan.getForegroundColor();
|
||||
boolean isBgDark = isColorDark(background);
|
||||
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
|
||||
foregroundColor, background, isBgDark);
|
||||
resultSpan = new ForegroundColorSpan(foregroundColor);
|
||||
}
|
||||
} else {
|
||||
@ -6247,12 +6296,28 @@ public class Notification implements Parcelable
|
||||
*
|
||||
* @param color the color to check
|
||||
* @return true if the color has higher contrast with white than black
|
||||
* @hide
|
||||
*/
|
||||
private static boolean isColorDark(int color) {
|
||||
public static boolean isColorDark(int color) {
|
||||
// as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
|
||||
return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a button fill color with sufficient contrast over bg (1.3:1) that has the same hue
|
||||
* as the original color, but is lightened or darkened depending on whether the background
|
||||
* is dark or light.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static int ensureButtonFillContrast(int color, int bg) {
|
||||
return isColorDark(bg)
|
||||
? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, 1.3)
|
||||
: ContrastColorUtil.findContrastColor(color, bg, true, 1.3);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Whether we are currently building a notification from a legacy (an app that
|
||||
* doesn't create material notifications by itself) app.
|
||||
@ -6441,25 +6506,34 @@ public class Notification implements Parcelable
|
||||
|
||||
if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
|
||||
&& !styleDisplaysCustomViewInline()) {
|
||||
if (mN.contentView == null) {
|
||||
mN.contentView = createContentView();
|
||||
RemoteViews newContentView = mN.contentView;
|
||||
RemoteViews newBigContentView = mN.bigContentView;
|
||||
RemoteViews newHeadsUpContentView = mN.headsUpContentView;
|
||||
if (newContentView == null) {
|
||||
newContentView = createContentView();
|
||||
mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
|
||||
mN.contentView.getSequenceNumber());
|
||||
newContentView.getSequenceNumber());
|
||||
}
|
||||
if (mN.bigContentView == null) {
|
||||
mN.bigContentView = createBigContentView();
|
||||
if (mN.bigContentView != null) {
|
||||
if (newBigContentView == null) {
|
||||
newBigContentView = createBigContentView();
|
||||
if (newBigContentView != null) {
|
||||
mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
|
||||
mN.bigContentView.getSequenceNumber());
|
||||
newBigContentView.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
if (mN.headsUpContentView == null) {
|
||||
mN.headsUpContentView = createHeadsUpContentView();
|
||||
if (mN.headsUpContentView != null) {
|
||||
if (newHeadsUpContentView == null) {
|
||||
newHeadsUpContentView = createHeadsUpContentView();
|
||||
if (newHeadsUpContentView != null) {
|
||||
mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
|
||||
mN.headsUpContentView.getSequenceNumber());
|
||||
newHeadsUpContentView.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
// Don't set any of the content views until after they have all been generated,
|
||||
// to avoid the generated .contentView triggering the logic which skips generating
|
||||
// the .bigContentView.
|
||||
mN.contentView = newContentView;
|
||||
mN.bigContentView = newBigContentView;
|
||||
mN.headsUpContentView = newHeadsUpContentView;
|
||||
}
|
||||
|
||||
if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
|
||||
@ -12305,6 +12379,8 @@ public class Notification implements Parcelable
|
||||
private int mSecondaryTextColor = COLOR_INVALID;
|
||||
private int mPrimaryAccentColor = COLOR_INVALID;
|
||||
private int mSecondaryAccentColor = COLOR_INVALID;
|
||||
private int mTertiaryAccentColor = COLOR_INVALID;
|
||||
private int mOnAccentTextColor = COLOR_INVALID;
|
||||
private int mErrorColor = COLOR_INVALID;
|
||||
private int mContrastColor = COLOR_INVALID;
|
||||
private int mRippleAlpha = 0x33;
|
||||
@ -12362,7 +12438,7 @@ public class Notification implements Parcelable
|
||||
|
||||
if (isColorized) {
|
||||
if (rawColor == COLOR_DEFAULT) {
|
||||
int[] attrs = {R.attr.colorAccentTertiary};
|
||||
int[] attrs = {R.attr.colorAccentSecondary};
|
||||
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
|
||||
mBackgroundColor = getColor(ta, 0, Color.WHITE);
|
||||
}
|
||||
@ -12379,6 +12455,8 @@ public class Notification implements Parcelable
|
||||
mContrastColor = mPrimaryTextColor;
|
||||
mPrimaryAccentColor = mPrimaryTextColor;
|
||||
mSecondaryAccentColor = mSecondaryTextColor;
|
||||
mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
|
||||
mOnAccentTextColor = mBackgroundColor;
|
||||
mErrorColor = mPrimaryTextColor;
|
||||
mRippleAlpha = 0x33;
|
||||
} else {
|
||||
@ -12389,6 +12467,8 @@ public class Notification implements Parcelable
|
||||
R.attr.textColorSecondary,
|
||||
R.attr.colorAccent,
|
||||
R.attr.colorAccentSecondary,
|
||||
R.attr.colorAccentTertiary,
|
||||
R.attr.textColorOnAccent,
|
||||
R.attr.colorError,
|
||||
R.attr.colorControlHighlight
|
||||
};
|
||||
@ -12399,8 +12479,10 @@ public class Notification implements Parcelable
|
||||
mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
|
||||
mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
|
||||
mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
|
||||
mErrorColor = getColor(ta, 6, COLOR_INVALID);
|
||||
mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
|
||||
mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
|
||||
mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
|
||||
mErrorColor = getColor(ta, 8, COLOR_INVALID);
|
||||
mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
|
||||
}
|
||||
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
|
||||
mBackgroundColor, nightMode);
|
||||
@ -12420,6 +12502,14 @@ public class Notification implements Parcelable
|
||||
if (mSecondaryAccentColor == COLOR_INVALID) {
|
||||
mSecondaryAccentColor = mContrastColor;
|
||||
}
|
||||
if (mTertiaryAccentColor == COLOR_INVALID) {
|
||||
mTertiaryAccentColor = mContrastColor;
|
||||
}
|
||||
if (mOnAccentTextColor == COLOR_INVALID) {
|
||||
mOnAccentTextColor = ColorUtils.setAlphaComponent(
|
||||
ContrastColorUtil.resolvePrimaryColor(
|
||||
ctx, mTertiaryAccentColor, nightMode), 0xFF);
|
||||
}
|
||||
if (mErrorColor == COLOR_INVALID) {
|
||||
mErrorColor = mPrimaryTextColor;
|
||||
}
|
||||
@ -12485,6 +12575,16 @@ public class Notification implements Parcelable
|
||||
return mSecondaryAccentColor;
|
||||
}
|
||||
|
||||
/** @return the theme's tertiary accent color for colored UI elements. */
|
||||
public @ColorInt int getTertiaryAccentColor() {
|
||||
return mTertiaryAccentColor;
|
||||
}
|
||||
|
||||
/** @return the theme's text color to be used on the tertiary accent color. */
|
||||
public @ColorInt int getOnAccentTextColor() {
|
||||
return mOnAccentTextColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the contrast-adjusted version of the color provided by the app, or the
|
||||
* primary text color when colorized.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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 > 0.
|
||||
* @param uid The user ID being checked against. A uid of 0 is the root
|
||||
|
@ -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.
|
||||
|
@ -1,5 +1,3 @@
|
||||
# Bug component: 722021
|
||||
|
||||
toddke@android.com
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
|
@ -1,6 +1,4 @@
|
||||
# Bug component: 568631
|
||||
|
||||
toddke@android.com
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
zyy@google.com
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,5 @@
|
||||
# Bug component: 86431
|
||||
|
||||
toddke@android.com
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
calin@google.com
|
||||
ngeoffray@google.com
|
||||
|
@ -2,4 +2,3 @@
|
||||
|
||||
chiuwinson@google.com
|
||||
patb@google.com
|
||||
toddke@google.com
|
||||
|
@ -2,7 +2,5 @@
|
||||
|
||||
include platform/frameworks/base:/core/java/android/permission/OWNERS
|
||||
|
||||
toddke@android.com
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
# Bug component: 36137
|
||||
|
||||
toddke@android.com
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
|
@ -2,4 +2,3 @@
|
||||
|
||||
chiuwinson@google.com
|
||||
patb@google.com
|
||||
toddke@google.com
|
@ -1,6 +1,4 @@
|
||||
# Bug component: 568761
|
||||
|
||||
toddke@android.com
|
||||
toddke@google.com
|
||||
patb@google.com
|
||||
zyy@google.com
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 |
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -873,21 +873,19 @@ 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<>();
|
||||
for (Request request : requests) {
|
||||
captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
|
||||
mCameraConfigMap));
|
||||
}
|
||||
seqId = mCaptureSession.captureBurstRequests(captureRequests,
|
||||
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to submit capture requests!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
try {
|
||||
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
||||
ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
|
||||
for (Request request : requests) {
|
||||
captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
|
||||
mCameraConfigMap));
|
||||
}
|
||||
seqId = mCaptureSession.captureBurstRequests(captureRequests,
|
||||
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to submit capture requests!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
|
||||
return seqId;
|
||||
@ -896,18 +894,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
@Override
|
||||
public int setRepeating(Request request, IRequestCallback callback) {
|
||||
int seqId = -1;
|
||||
synchronized (mInterfaceLock) {
|
||||
try {
|
||||
CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
|
||||
request, mCameraConfigMap);
|
||||
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
||||
seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
|
||||
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to enable repeating request!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
try {
|
||||
CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
|
||||
request, mCameraConfigMap);
|
||||
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
||||
seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
|
||||
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to enable repeating request!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
|
||||
return seqId;
|
||||
@ -915,27 +911,23 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
|
||||
@Override
|
||||
public void abortCaptures() {
|
||||
synchronized (mInterfaceLock) {
|
||||
try {
|
||||
mCaptureSession.abortCaptures();
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed during capture abort!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
try {
|
||||
mCaptureSession.abortCaptures();
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed during capture abort!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRepeating() {
|
||||
synchronized (mInterfaceLock) {
|
||||
try {
|
||||
mCaptureSession.stopRepeating();
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed during repeating capture stop!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
try {
|
||||
mCaptureSession.stopRepeating();
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed during repeating capture stop!");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Capture session closed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
mFrameNumberTracker.updateTracker(frameNumber,
|
||||
/*error*/true, request.getRequestType());
|
||||
|
||||
// Update FrameNumberTracker for every frame during HFR mode.
|
||||
if (mBatchOutputMap.containsKey(requestId)) {
|
||||
for (int i = 0; i < mBatchOutputMap.get(requestId); i++) {
|
||||
mFrameNumberTracker.updateTracker(frameNumber - (subsequenceId - i),
|
||||
/*error*/true, request.getRequestType());
|
||||
}
|
||||
} else {
|
||||
mFrameNumberTracker.updateTracker(frameNumber,
|
||||
/*error*/true, request.getRequestType());
|
||||
}
|
||||
|
||||
checkAndFireSequenceComplete();
|
||||
|
||||
// Dispatch the failure callback
|
||||
@ -2023,7 +2080,6 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
public void onResultReceived(CameraMetadataNative result,
|
||||
CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
|
||||
throws RemoteException {
|
||||
|
||||
int requestId = resultExtras.getRequestId();
|
||||
long frameNumber = resultExtras.getFrameNumber();
|
||||
|
||||
@ -2064,8 +2120,8 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
+ frameNumber);
|
||||
}
|
||||
|
||||
mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
|
||||
requestType);
|
||||
updateTracker(requestId, frameNumber, requestType, /*result*/null,
|
||||
isPartialResult);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -2077,8 +2133,9 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
+ frameNumber);
|
||||
}
|
||||
|
||||
mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
|
||||
requestType);
|
||||
updateTracker(requestId, frameNumber, requestType, /*result*/null,
|
||||
isPartialResult);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2184,9 +2241,7 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
|
||||
// Collect the partials for a total result; or mark the frame as totally completed
|
||||
mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
|
||||
requestType);
|
||||
updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult);
|
||||
|
||||
// Fire onCaptureSequenceCompleted
|
||||
if (!isPartialResult) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ import java.util.List;
|
||||
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
|
||||
|
||||
private static final String TAG = "FaceManager";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private static final int MSG_ENROLL_RESULT = 100;
|
||||
private static final int MSG_ACQUIRED = 101;
|
||||
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
|
||||
@ -207,13 +207,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
throw new IllegalArgumentException("Must supply an authentication callback");
|
||||
}
|
||||
|
||||
if (cancel != null) {
|
||||
if (cancel.isCanceled()) {
|
||||
Slog.w(TAG, "authentication already canceled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
|
||||
}
|
||||
if (cancel != null && cancel.isCanceled()) {
|
||||
Slog.w(TAG, "authentication already canceled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mService != null) {
|
||||
@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
mCryptoObject = crypto;
|
||||
final long operationId = crypto != null ? crypto.getOpId() : 0;
|
||||
Trace.beginSection("FaceManager#authenticate");
|
||||
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
|
||||
mContext.getOpPackageName(), isKeyguardBypassEnabled);
|
||||
final long authId = mService.authenticate(mToken, operationId, userId,
|
||||
mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
|
||||
if (cancel != null) {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
||||
if (callback != null) {
|
||||
// Though this may not be a hardware issue, it will cause apps to give up or
|
||||
// try again later.
|
||||
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
|
||||
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */));
|
||||
}
|
||||
// Though this may not be a hardware issue, it will cause apps to give up or
|
||||
// try again later.
|
||||
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
|
||||
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */));
|
||||
} finally {
|
||||
Trace.endSection();
|
||||
}
|
||||
@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
if (cancel.isCanceled()) {
|
||||
Slog.w(TAG, "Detection already cancelled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
|
||||
}
|
||||
|
||||
mFaceDetectionCallback = callback;
|
||||
|
||||
try {
|
||||
mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
|
||||
final long authId = mService.detectFace(
|
||||
mToken, userId, mServiceReceiver, mContext.getOpPackageName());
|
||||
cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId));
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception when requesting finger detect", e);
|
||||
}
|
||||
@ -726,23 +723,23 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAuthentication(CryptoObject cryptoObject) {
|
||||
private void cancelAuthentication(long requestId) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
|
||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelFaceDetect() {
|
||||
private void cancelFaceDetect(long requestId) {
|
||||
if (mService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mService.cancelFaceDetect(mToken, mContext.getOpPackageName());
|
||||
mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@ -794,9 +791,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
// This is used as a last resort in case a vendor string is missing
|
||||
// It should not happen for anything other than FACE_ERROR_VENDOR, but
|
||||
// warn and use the default if all else fails.
|
||||
// TODO(b/196639965): update string
|
||||
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
|
||||
return "";
|
||||
return context.getString(
|
||||
com.android.internal.R.string.face_error_vendor_unknown);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1110,22 +1107,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
}
|
||||
|
||||
private class OnAuthenticationCancelListener implements OnCancelListener {
|
||||
private final CryptoObject mCrypto;
|
||||
private final long mAuthRequestId;
|
||||
|
||||
OnAuthenticationCancelListener(CryptoObject crypto) {
|
||||
mCrypto = crypto;
|
||||
OnAuthenticationCancelListener(long id) {
|
||||
mAuthRequestId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancelAuthentication(mCrypto);
|
||||
Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId);
|
||||
cancelAuthentication(mAuthRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
private class OnFaceDetectionCancelListener implements OnCancelListener {
|
||||
private final long mAuthRequestId;
|
||||
|
||||
OnFaceDetectionCancelListener(long id) {
|
||||
mAuthRequestId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancelFaceDetect();
|
||||
Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId);
|
||||
cancelFaceDetect(mAuthRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -146,6 +146,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
private CryptoObject mCryptoObject;
|
||||
@Nullable private RemoveTracker mRemoveTracker;
|
||||
private Handler mHandler;
|
||||
@Nullable private float[] mEnrollStageThresholds;
|
||||
|
||||
/**
|
||||
* Retrieves a list of properties for all fingerprint sensors on the device.
|
||||
@ -189,22 +190,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
}
|
||||
|
||||
private class OnAuthenticationCancelListener implements OnCancelListener {
|
||||
private android.hardware.biometrics.CryptoObject mCrypto;
|
||||
private final long mAuthRequestId;
|
||||
|
||||
public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
|
||||
mCrypto = crypto;
|
||||
OnAuthenticationCancelListener(long id) {
|
||||
mAuthRequestId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancelAuthentication(mCrypto);
|
||||
Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
|
||||
cancelAuthentication(mAuthRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
private class OnFingerprintDetectionCancelListener implements OnCancelListener {
|
||||
private final long mAuthRequestId;
|
||||
|
||||
OnFingerprintDetectionCancelListener(long id) {
|
||||
mAuthRequestId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancelFingerprintDetect();
|
||||
Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId);
|
||||
cancelFingerprintDetect(mAuthRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,13 +561,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
throw new IllegalArgumentException("Must supply an authentication callback");
|
||||
}
|
||||
|
||||
if (cancel != null) {
|
||||
if (cancel.isCanceled()) {
|
||||
Slog.w(TAG, "authentication already canceled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
|
||||
}
|
||||
if (cancel != null && cancel.isCanceled()) {
|
||||
Slog.w(TAG, "authentication already canceled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mService != null) {
|
||||
@ -567,8 +572,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
mAuthenticationCallback = callback;
|
||||
mCryptoObject = crypto;
|
||||
final long operationId = crypto != null ? crypto.getOpId() : 0;
|
||||
mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver,
|
||||
mContext.getOpPackageName());
|
||||
final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
|
||||
mServiceReceiver, mContext.getOpPackageName());
|
||||
if (cancel != null) {
|
||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
||||
// Though this may not be a hardware issue, it will cause apps to give up or try
|
||||
@ -595,15 +603,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
if (cancel.isCanceled()) {
|
||||
Slog.w(TAG, "Detection already cancelled");
|
||||
return;
|
||||
} else {
|
||||
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
|
||||
}
|
||||
|
||||
mFingerprintDetectionCallback = callback;
|
||||
|
||||
try {
|
||||
mService.detectFingerprint(mToken, userId, mServiceReceiver,
|
||||
final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
|
||||
mContext.getOpPackageName());
|
||||
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Remote exception when requesting finger detect", e);
|
||||
}
|
||||
@ -843,26 +850,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
return hasEnrolledFingerprints(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified user has enrollments in any of the specified sensors.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
public boolean hasEnrolledTemplatesForAnySensor(int userId,
|
||||
@NonNull List<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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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) {};
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint;
|
||||
*/
|
||||
oneway interface IFingerprintStateListener {
|
||||
void onStateChanged(int newState);
|
||||
void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
|
@ -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,28 +544,21 @@ public class GraphicsEnvironment {
|
||||
|
||||
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
|
||||
|
||||
// If the user has set the developer option to something other than default,
|
||||
// we need to call setupAngleRulesApk() with the package name and the developer
|
||||
// option value (native/angle/other). Then later when we are actually trying to
|
||||
// load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before
|
||||
// and can confidently answer yes/no based on the previously set developer
|
||||
// option value.
|
||||
final String devOptIn = getDriverForPackage(context, bundle, packageName);
|
||||
|
||||
if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
|
||||
// We setup ANGLE with a temp rules file, so we're done here.
|
||||
return true;
|
||||
// We need to call setAngleInfo() with the package name and the developer option value
|
||||
//(native/angle/other). Then later when we are actually trying to load a driver,
|
||||
//GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
|
||||
//answer yes/no based on the previously set developer option value.
|
||||
final String devOptIn;
|
||||
final String[] features = getAngleEglFeatures(context, bundle);
|
||||
final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
|
||||
if (gameModeEnabledAngle) {
|
||||
devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
|
||||
} else {
|
||||
devOptIn = getDriverForPackage(context, bundle, packageName);
|
||||
}
|
||||
setAngleInfo(paths, packageName, devOptIn, features);
|
||||
|
||||
String[] features = getAngleEglFeatures(context, bundle);
|
||||
|
||||
if (setupAngleRulesApk(
|
||||
anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
|
||||
// ANGLE with rules is set up from the APK, hence return.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -956,7 +846,7 @@ public class GraphicsEnvironment {
|
||||
private static native void setGpuStats(String driverPackageName, String driverVersionName,
|
||||
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
|
||||
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
|
||||
String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength);
|
||||
String[] features);
|
||||
private static native boolean getShouldUseAngle(String packageName);
|
||||
private static native boolean setInjectLayersPrSetDumpable();
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
# Bug component: 554432
|
||||
alexbuy@google.com
|
||||
schfan@google.com
|
||||
toddke@google.com
|
||||
zyy@google.com
|
||||
patb@google.com
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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}></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> <translation-service
|
||||
* android:settingsActivity="foo.bar.SettingsActivity"
|
||||
* . . .
|
||||
* /></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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)")
|
||||
|
@ -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 []")
|
||||
|
@ -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 []")
|
||||
|
@ -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 (DEBUG) {
|
||||
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
|
||||
+ ". Ignoring.");
|
||||
if (callback instanceof TextViewTranslationCallback) {
|
||||
if (((TextViewTranslationCallback) callback).isShowingTranslation()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
|
||||
+ ". Ignoring.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
ViewTranslationCallback callback = view.getViewTranslationCallback();
|
||||
if (callback == null) {
|
||||
if (view instanceof TextView) {
|
||||
// developer doesn't provide their override, we set the default TextView
|
||||
@ -590,9 +602,8 @@ public class UiTranslationController {
|
||||
final View rootView = roots.get(rootNum).getView();
|
||||
if (rootView instanceof ViewGroup) {
|
||||
findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds);
|
||||
} else {
|
||||
addViewIfNeeded(sourceViewIds, rootView);
|
||||
}
|
||||
addViewIfNeeded(sourceViewIds, rootView);
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,9 +614,8 @@ public class UiTranslationController {
|
||||
final View child = viewGroup.getChildAt(i);
|
||||
if (child instanceof ViewGroup) {
|
||||
findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds);
|
||||
} else {
|
||||
addViewIfNeeded(sourceViewIds, child);
|
||||
}
|
||||
addViewIfNeeded(sourceViewIds, child);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
0
core/java/com/android/internal/infra/OWNERS
Normal file
0
core/java/com/android/internal/infra/OWNERS
Normal 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));
|
||||
}
|
||||
// We don't remove observer here,
|
||||
// will remove it when all the frame metrics in this duration are called back.
|
||||
// See onFrameMetricsAvailable for the logic of removing the observer.
|
||||
}
|
||||
|
||||
/**
|
||||
@ -396,7 +404,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
}
|
||||
|
||||
private void finish(int indexOnOrAfterEnd) {
|
||||
|
||||
mHandler.removeCallbacks(mWaitForFinishTimedOut);
|
||||
mWaitForFinishTimedOut = null;
|
||||
mMetricsFinalized = true;
|
||||
|
||||
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
|
||||
@ -481,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
|
||||
Log.i(TAG, "finish: CUJ=" + mSession.getName()
|
||||
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
|
||||
+ " totalFrames=" + totalFramesCount
|
||||
+ " missedAppFrames=" + missedAppFramesCount
|
||||
|
@ -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 =
|
||||
|
@ -707,6 +707,10 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
* Mapping isolated uids to the actual owning app uid.
|
||||
*/
|
||||
final SparseIntArray mIsolatedUids = new SparseIntArray();
|
||||
/**
|
||||
* Internal reference count of isolated uids.
|
||||
*/
|
||||
final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray();
|
||||
|
||||
/**
|
||||
* The statistics we have collected organized by uids.
|
||||
@ -3897,6 +3901,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
public void addIsolatedUidLocked(int isolatedUid, int appUid,
|
||||
long elapsedRealtimeMs, long uptimeMs) {
|
||||
mIsolatedUids.put(isolatedUid, appUid);
|
||||
mIsolatedUidRefCounts.put(isolatedUid, 1);
|
||||
final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
|
||||
u.addIsolatedUid(isolatedUid);
|
||||
}
|
||||
@ -3915,19 +3920,51 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be called after the cpu times have been read.
|
||||
* Isolated uid should only be removed after all wakelocks associated with the uid are stopped
|
||||
* and the cpu time-in-state has been read one last time for the uid.
|
||||
*
|
||||
* @see #scheduleRemoveIsolatedUidLocked(int, int)
|
||||
*
|
||||
* @return true if the isolated uid is actually removed.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
|
||||
public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs,
|
||||
long uptimeMs) {
|
||||
final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1;
|
||||
if (refCount > 0) {
|
||||
// Isolated uid is still being tracked
|
||||
mIsolatedUidRefCounts.put(isolatedUid, refCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
|
||||
if (idx >= 0) {
|
||||
final int ownerUid = mIsolatedUids.valueAt(idx);
|
||||
final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
|
||||
u.removeIsolatedUid(isolatedUid);
|
||||
mIsolatedUids.removeAt(idx);
|
||||
mIsolatedUidRefCounts.delete(isolatedUid);
|
||||
} else {
|
||||
Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")");
|
||||
}
|
||||
mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the ref count for an isolated uid.
|
||||
* call #maybeRemoveIsolatedUidLocked to decrement.
|
||||
*/
|
||||
public void incrementIsolatedUidRefCount(int uid) {
|
||||
final int refCount = mIsolatedUidRefCounts.get(uid, 0);
|
||||
if (refCount <= 0) {
|
||||
// Uid is not mapped or referenced
|
||||
Slog.w(TAG,
|
||||
"Attempted to increment ref counted of untracked isolated uid (" + uid + ")");
|
||||
return;
|
||||
}
|
||||
mIsolatedUidRefCounts.put(uid, refCount + 1);
|
||||
}
|
||||
|
||||
public int mapUid(int uid) {
|
||||
@ -4287,7 +4324,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
|
||||
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
|
||||
int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
|
||||
uid = mapUid(uid);
|
||||
final int mappedUid = mapUid(uid);
|
||||
if (type == WAKE_TYPE_PARTIAL) {
|
||||
// Only care about partial wake locks, since full wake locks
|
||||
// will be canceled when the user puts the screen to sleep.
|
||||
@ -4297,9 +4334,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
if (mRecordAllHistory) {
|
||||
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
|
||||
uid, 0)) {
|
||||
mappedUid, 0)) {
|
||||
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
|
||||
HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
|
||||
HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid);
|
||||
}
|
||||
}
|
||||
if (mWakeLockNesting == 0) {
|
||||
@ -4308,7 +4345,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
+ Integer.toHexString(mHistoryCur.states));
|
||||
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
|
||||
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
|
||||
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
|
||||
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
|
||||
mWakeLockImportant = !unimportantForLogging;
|
||||
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
||||
} else if (!mWakeLockImportant && !unimportantForLogging
|
||||
@ -4318,14 +4355,19 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mHistoryLastWritten.wakelockTag = null;
|
||||
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
|
||||
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
|
||||
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
|
||||
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
|
||||
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
||||
}
|
||||
mWakeLockImportant = true;
|
||||
}
|
||||
mWakeLockNesting++;
|
||||
}
|
||||
if (uid >= 0) {
|
||||
if (mappedUid >= 0) {
|
||||
if (mappedUid != uid) {
|
||||
// Prevent the isolated uid mapping from being removed while the wakelock is
|
||||
// being held.
|
||||
incrementIsolatedUidRefCount(uid);
|
||||
}
|
||||
if (mOnBatteryScreenOffTimeBase.isRunning()) {
|
||||
// We only update the cpu time when a wake lock is acquired if the screen is off.
|
||||
// If the screen is on, we don't distribute the power amongst partial wakelocks.
|
||||
@ -4335,7 +4377,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
requestWakelockCpuUpdate();
|
||||
}
|
||||
|
||||
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
|
||||
getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
|
||||
.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
|
||||
|
||||
if (wc != null) {
|
||||
@ -4343,8 +4385,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
|
||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
|
||||
} else {
|
||||
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
|
||||
null, getPowerManagerWakeLockLevel(type), name,
|
||||
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
|
||||
mappedUid, null, getPowerManagerWakeLockLevel(type), name,
|
||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
|
||||
}
|
||||
}
|
||||
@ -4358,7 +4400,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
|
||||
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
|
||||
int type, long elapsedRealtimeMs, long uptimeMs) {
|
||||
uid = mapUid(uid);
|
||||
final int mappedUid = mapUid(uid);
|
||||
if (type == WAKE_TYPE_PARTIAL) {
|
||||
mWakeLockNesting--;
|
||||
if (mRecordAllHistory) {
|
||||
@ -4366,9 +4408,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
historyName = name;
|
||||
}
|
||||
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
|
||||
uid, 0)) {
|
||||
mappedUid, 0)) {
|
||||
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
|
||||
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
|
||||
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid);
|
||||
}
|
||||
}
|
||||
if (mWakeLockNesting == 0) {
|
||||
@ -4380,7 +4422,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
||||
}
|
||||
}
|
||||
if (uid >= 0) {
|
||||
if (mappedUid >= 0) {
|
||||
if (mOnBatteryScreenOffTimeBase.isRunning()) {
|
||||
if (DEBUG_ENERGY_CPU) {
|
||||
Slog.d(TAG, "Updating cpu time because of -wake_lock");
|
||||
@ -4388,17 +4430,22 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
requestWakelockCpuUpdate();
|
||||
}
|
||||
|
||||
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
|
||||
getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
|
||||
.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
|
||||
if (wc != null) {
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
|
||||
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
|
||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
|
||||
} else {
|
||||
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
|
||||
null, getPowerManagerWakeLockLevel(type), name,
|
||||
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
|
||||
mappedUid, null, getPowerManagerWakeLockLevel(type), name,
|
||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
|
||||
}
|
||||
|
||||
if (mappedUid != uid) {
|
||||
// Decrement the ref count for the isolated uid and delete the mapping if uneeded.
|
||||
maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8571,7 +8618,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
* inactive so can be dropped.
|
||||
*/
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||
public boolean reset(long uptimeUs, long realtimeUs) {
|
||||
public boolean reset(long uptimeUs, long realtimeUs, int resetReason) {
|
||||
boolean active = false;
|
||||
|
||||
mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs);
|
||||
@ -8641,7 +8688,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs);
|
||||
resetIfNotNull(mModemControllerActivity, false, realtimeUs);
|
||||
|
||||
MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats);
|
||||
if (resetReason == RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE) {
|
||||
mUidMeasuredEnergyStats = null;
|
||||
} else {
|
||||
MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats);
|
||||
}
|
||||
|
||||
resetIfNotNull(mUserCpuTime, false, realtimeUs);
|
||||
resetIfNotNull(mSystemCpuTime, false, realtimeUs);
|
||||
@ -11324,7 +11375,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mNumConnectivityChange = 0;
|
||||
|
||||
for (int i=0; i<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);
|
||||
|
||||
|
@ -29,6 +29,7 @@ import android.util.SparseArray;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -234,8 +235,9 @@ public class BatteryUsageStatsProvider {
|
||||
final boolean includePowerModels = (query.getFlags()
|
||||
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
|
||||
|
||||
final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames();
|
||||
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
|
||||
mStats.getCustomEnergyConsumerNames(), includePowerModels);
|
||||
customEnergyConsumerNames, includePowerModels);
|
||||
if (mBatteryUsageStatsStore == null) {
|
||||
Log.e(TAG, "BatteryUsageStatsStore is unavailable");
|
||||
return builder.build();
|
||||
@ -247,7 +249,14 @@ public class BatteryUsageStatsProvider {
|
||||
final BatteryUsageStats snapshot =
|
||||
mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
|
||||
if (snapshot != null) {
|
||||
builder.add(snapshot);
|
||||
if (Arrays.equals(snapshot.getCustomPowerComponentNames(),
|
||||
customEnergyConsumerNames)) {
|
||||
builder.add(snapshot);
|
||||
} else {
|
||||
Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different "
|
||||
+ "custom power components: "
|
||||
+ Arrays.toString(snapshot.getCustomPowerComponentNames()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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
|
@ -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
|
||||
*/
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user