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();
|
reasonCode, reason).sendToTarget();
|
||||||
}
|
}
|
||||||
reportTempWhitelistChangedLocked(uid, true);
|
reportTempWhitelistChangedLocked(uid, true);
|
||||||
|
} else {
|
||||||
|
// The uid is already temp allowlisted, only need to update AMS for temp allowlist
|
||||||
|
// duration.
|
||||||
|
if (mLocalActivityManager != null) {
|
||||||
|
mLocalActivityManager.updateDeviceIdleTempAllowlist(null, uid, true,
|
||||||
|
duration, tempAllowListType, reasonCode, reason, callingUid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (informWhitelistChanged) {
|
if (informWhitelistChanged) {
|
||||||
@ -3941,6 +3948,10 @@ public class DeviceIdleController extends SystemService
|
|||||||
if (idleUntil) {
|
if (idleUntil) {
|
||||||
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||||
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
|
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
|
||||||
|
} else if (mState == STATE_LOCATING) {
|
||||||
|
// Use setExact so we don't keep the GPS active for too long.
|
||||||
|
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||||
|
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
|
||||||
} else {
|
} else {
|
||||||
if (mConstants.USE_WINDOW_ALARMS) {
|
if (mConstants.USE_WINDOW_ALARMS) {
|
||||||
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||||
|
@ -71,7 +71,7 @@ cc_library_shared {
|
|||||||
"libui",
|
"libui",
|
||||||
"libjnigraphics",
|
"libjnigraphics",
|
||||||
"libEGL",
|
"libEGL",
|
||||||
"libGLESv1_CM",
|
"libGLESv2",
|
||||||
"libgui",
|
"libgui",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,8 @@
|
|||||||
#include <gui/DisplayEventReceiver.h>
|
#include <gui/DisplayEventReceiver.h>
|
||||||
#include <gui/Surface.h>
|
#include <gui/Surface.h>
|
||||||
#include <gui/SurfaceComposerClient.h>
|
#include <gui/SurfaceComposerClient.h>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
#include <GLES/gl.h>
|
#include <GLES2/gl2ext.h>
|
||||||
#include <GLES/glext.h>
|
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
#include "BootAnimation.h"
|
#include "BootAnimation.h"
|
||||||
@ -108,6 +107,93 @@ static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress";
|
|||||||
static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
|
static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
|
||||||
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
|
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
|
||||||
static constexpr size_t TEXT_POS_LEN_MAX = 16;
|
static constexpr size_t TEXT_POS_LEN_MAX = 16;
|
||||||
|
static const int DYNAMIC_COLOR_COUNT = 4;
|
||||||
|
static const char U_TEXTURE[] = "uTexture";
|
||||||
|
static const char U_FADE[] = "uFade";
|
||||||
|
static const char U_CROP_AREA[] = "uCropArea";
|
||||||
|
static const char U_START_COLOR_PREFIX[] = "uStartColor";
|
||||||
|
static const char U_END_COLOR_PREFIX[] = "uEndColor";
|
||||||
|
static const char U_COLOR_PROGRESS[] = "uColorProgress";
|
||||||
|
static const char A_UV[] = "aUv";
|
||||||
|
static const char A_POSITION[] = "aPosition";
|
||||||
|
static const char VERTEX_SHADER_SOURCE[] = R"(
|
||||||
|
precision mediump float;
|
||||||
|
attribute vec4 aPosition;
|
||||||
|
attribute highp vec2 aUv;
|
||||||
|
varying highp vec2 vUv;
|
||||||
|
void main() {
|
||||||
|
gl_Position = aPosition;
|
||||||
|
vUv = aUv;
|
||||||
|
})";
|
||||||
|
static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
|
||||||
|
precision mediump float;
|
||||||
|
const float cWhiteMaskThreshold = 0.05;
|
||||||
|
uniform sampler2D uTexture;
|
||||||
|
uniform float uFade;
|
||||||
|
uniform float uColorProgress;
|
||||||
|
uniform vec4 uStartColor0;
|
||||||
|
uniform vec4 uStartColor1;
|
||||||
|
uniform vec4 uStartColor2;
|
||||||
|
uniform vec4 uStartColor3;
|
||||||
|
uniform vec4 uEndColor0;
|
||||||
|
uniform vec4 uEndColor1;
|
||||||
|
uniform vec4 uEndColor2;
|
||||||
|
uniform vec4 uEndColor3;
|
||||||
|
varying highp vec2 vUv;
|
||||||
|
void main() {
|
||||||
|
vec4 mask = texture2D(uTexture, vUv);
|
||||||
|
float r = mask.r;
|
||||||
|
float g = mask.g;
|
||||||
|
float b = mask.b;
|
||||||
|
float a = mask.a;
|
||||||
|
// If all channels have values, render pixel as a shade of white.
|
||||||
|
float useWhiteMask = step(cWhiteMaskThreshold, r)
|
||||||
|
* step(cWhiteMaskThreshold, g)
|
||||||
|
* step(cWhiteMaskThreshold, b)
|
||||||
|
* step(cWhiteMaskThreshold, a);
|
||||||
|
vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress)
|
||||||
|
+ g * mix(uStartColor1, uEndColor1, uColorProgress)
|
||||||
|
+ b * mix(uStartColor2, uEndColor2, uColorProgress)
|
||||||
|
+ a * mix(uStartColor3, uEndColor3, uColorProgress);
|
||||||
|
color = mix(color, vec4(vec3((r + g + b + a) * 0.25), 1.0), useWhiteMask);
|
||||||
|
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
|
||||||
|
})";
|
||||||
|
static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
|
||||||
|
precision mediump float;
|
||||||
|
uniform sampler2D uTexture;
|
||||||
|
uniform float uFade;
|
||||||
|
varying highp vec2 vUv;
|
||||||
|
void main() {
|
||||||
|
vec4 color = texture2D(uTexture, vUv);
|
||||||
|
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
|
||||||
|
})";
|
||||||
|
static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
|
||||||
|
precision mediump float;
|
||||||
|
uniform sampler2D uTexture;
|
||||||
|
uniform vec4 uCropArea;
|
||||||
|
varying highp vec2 vUv;
|
||||||
|
void main() {
|
||||||
|
vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x),
|
||||||
|
mix(uCropArea.y, uCropArea.w, vUv.y));
|
||||||
|
gl_FragColor = texture2D(uTexture, uv);
|
||||||
|
})";
|
||||||
|
|
||||||
|
static GLfloat quadPositions[] = {
|
||||||
|
-0.5f, -0.5f,
|
||||||
|
+0.5f, -0.5f,
|
||||||
|
+0.5f, +0.5f,
|
||||||
|
+0.5f, +0.5f,
|
||||||
|
-0.5f, +0.5f,
|
||||||
|
-0.5f, -0.5f
|
||||||
|
};
|
||||||
|
static GLfloat quadUVs[] = {
|
||||||
|
0.0f, 1.0f,
|
||||||
|
1.0f, 1.0f,
|
||||||
|
1.0f, 0.0f,
|
||||||
|
1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -163,7 +249,8 @@ void BootAnimation::binderDied(const wp<IBinder>&) {
|
|||||||
requestExit();
|
requestExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) {
|
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo,
|
||||||
|
bool premultiplyAlpha) {
|
||||||
AImageDecoder* decoder = nullptr;
|
AImageDecoder* decoder = nullptr;
|
||||||
AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
|
AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
|
||||||
if (!decoder) {
|
if (!decoder) {
|
||||||
@ -177,6 +264,10 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
|
|||||||
outInfo->stride = AImageDecoder_getMinimumStride(decoder);
|
outInfo->stride = AImageDecoder_getMinimumStride(decoder);
|
||||||
outInfo->flags = 0;
|
outInfo->flags = 0;
|
||||||
|
|
||||||
|
if (!premultiplyAlpha) {
|
||||||
|
AImageDecoder_setUnpremultipliedRequired(decoder, true);
|
||||||
|
}
|
||||||
|
|
||||||
const size_t size = outInfo->stride * outInfo->height;
|
const size_t size = outInfo->stride * outInfo->height;
|
||||||
void* pixels = malloc(size);
|
void* pixels = malloc(size);
|
||||||
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
|
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
|
||||||
@ -190,13 +281,14 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
|
|||||||
}
|
}
|
||||||
|
|
||||||
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
|
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
|
||||||
const char* name) {
|
const char* name, bool premultiplyAlpha) {
|
||||||
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
|
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
|
||||||
if (asset == nullptr)
|
if (asset == nullptr)
|
||||||
return NO_INIT;
|
return NO_INIT;
|
||||||
|
|
||||||
AndroidBitmapInfo bitmapInfo;
|
AndroidBitmapInfo bitmapInfo;
|
||||||
void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo);
|
void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo,
|
||||||
|
premultiplyAlpha);
|
||||||
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
|
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
|
||||||
|
|
||||||
asset->close();
|
asset->close();
|
||||||
@ -209,7 +301,6 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
|
|||||||
const int w = bitmapInfo.width;
|
const int w = bitmapInfo.width;
|
||||||
const int h = bitmapInfo.height;
|
const int h = bitmapInfo.height;
|
||||||
|
|
||||||
GLint crop[4] = { 0, h, w, -h };
|
|
||||||
texture->w = w;
|
texture->w = w;
|
||||||
texture->h = h;
|
texture->h = h;
|
||||||
|
|
||||||
@ -237,18 +328,19 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
|
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
|
||||||
|
bool premultiplyAlpha) {
|
||||||
AndroidBitmapInfo bitmapInfo;
|
AndroidBitmapInfo bitmapInfo;
|
||||||
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo);
|
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
|
||||||
|
premultiplyAlpha);
|
||||||
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
|
auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };
|
||||||
|
|
||||||
// FileMap memory is never released until application exit.
|
// FileMap memory is never released until application exit.
|
||||||
@ -263,7 +355,6 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
|
|||||||
const int w = bitmapInfo.width;
|
const int w = bitmapInfo.width;
|
||||||
const int h = bitmapInfo.height;
|
const int h = bitmapInfo.height;
|
||||||
|
|
||||||
GLint crop[4] = { 0, h, w, -h };
|
|
||||||
int tw = 1 << (31 - __builtin_clz(w));
|
int tw = 1 << (31 - __builtin_clz(w));
|
||||||
int th = 1 << (31 - __builtin_clz(h));
|
int th = 1 << (31 - __builtin_clz(h));
|
||||||
if (tw < w) tw <<= 1;
|
if (tw < w) tw <<= 1;
|
||||||
@ -297,7 +388,10 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
*width = w;
|
*width = w;
|
||||||
*height = h;
|
*height = h;
|
||||||
@ -470,7 +564,9 @@ status_t BootAnimation::readyToRun() {
|
|||||||
eglInitialize(display, nullptr, nullptr);
|
eglInitialize(display, nullptr, nullptr);
|
||||||
EGLConfig config = getEglConfig(display);
|
EGLConfig config = getEglConfig(display);
|
||||||
EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
|
EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
|
||||||
EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
|
// Initialize egl context with client version number 2.0.
|
||||||
|
EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
||||||
|
EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
|
||||||
EGLint w, h;
|
EGLint w, h;
|
||||||
eglQuerySurface(display, surface, EGL_WIDTH, &w);
|
eglQuerySurface(display, surface, EGL_WIDTH, &w);
|
||||||
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
|
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
|
||||||
@ -503,11 +599,6 @@ status_t BootAnimation::readyToRun() {
|
|||||||
void BootAnimation::projectSceneToWindow() {
|
void BootAnimation::projectSceneToWindow() {
|
||||||
glViewport(0, 0, mWidth, mHeight);
|
glViewport(0, 0, mWidth, mHeight);
|
||||||
glScissor(0, 0, mWidth, mHeight);
|
glScissor(0, 0, mWidth, mHeight);
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BootAnimation::resizeSurface(int newWidth, int newHeight) {
|
void BootAnimation::resizeSurface(int newWidth, int newHeight) {
|
||||||
@ -600,8 +691,76 @@ void BootAnimation::findBootAnimationFile() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLuint compileShader(GLenum shaderType, const GLchar *source) {
|
||||||
|
GLuint shader = glCreateShader(shaderType);
|
||||||
|
glShaderSource(shader, 1, &source, 0);
|
||||||
|
glCompileShader(shader);
|
||||||
|
GLint isCompiled = 0;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
|
||||||
|
if (isCompiled == GL_FALSE) {
|
||||||
|
SLOGE("Compile shader failed. Shader type: %d", shaderType);
|
||||||
|
GLint maxLength = 0;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
|
||||||
|
std::vector<GLchar> errorLog(maxLength);
|
||||||
|
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
|
||||||
|
SLOGE("Shader compilation error: %s", &errorLog[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
glAttachShader(program, vertexShader);
|
||||||
|
glAttachShader(program, fragmentShader);
|
||||||
|
glLinkProgram(program);
|
||||||
|
GLint isLinked = 0;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
|
||||||
|
if (isLinked == GL_FALSE) {
|
||||||
|
SLOGE("Linking shader failed. Shader handles: vert %d, frag %d",
|
||||||
|
vertexShader, fragmentShader);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BootAnimation::initShaders() {
|
||||||
|
bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
|
||||||
|
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
|
||||||
|
GLuint imageFragmentShader =
|
||||||
|
compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled
|
||||||
|
? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE
|
||||||
|
: (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
|
||||||
|
GLuint textFragmentShader =
|
||||||
|
compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
|
||||||
|
|
||||||
|
// Initialize image shader.
|
||||||
|
mImageShader = linkShader(vertexShader, imageFragmentShader);
|
||||||
|
GLint positionLocation = glGetAttribLocation(mImageShader, A_POSITION);
|
||||||
|
GLint uvLocation = glGetAttribLocation(mImageShader, A_UV);
|
||||||
|
mImageTextureLocation = glGetUniformLocation(mImageShader, U_TEXTURE);
|
||||||
|
mImageFadeLocation = glGetUniformLocation(mImageShader, U_FADE);
|
||||||
|
glEnableVertexAttribArray(positionLocation);
|
||||||
|
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions);
|
||||||
|
glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
|
||||||
|
glEnableVertexAttribArray(uvLocation);
|
||||||
|
|
||||||
|
// Initialize text shader.
|
||||||
|
mTextShader = linkShader(vertexShader, textFragmentShader);
|
||||||
|
positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
|
||||||
|
uvLocation = glGetAttribLocation(mTextShader, A_UV);
|
||||||
|
mTextTextureLocation = glGetUniformLocation(mTextShader, U_TEXTURE);
|
||||||
|
mTextCropAreaLocation = glGetUniformLocation(mTextShader, U_CROP_AREA);
|
||||||
|
glEnableVertexAttribArray(positionLocation);
|
||||||
|
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions);
|
||||||
|
glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
|
||||||
|
glEnableVertexAttribArray(uvLocation);
|
||||||
|
}
|
||||||
|
|
||||||
bool BootAnimation::threadLoop() {
|
bool BootAnimation::threadLoop() {
|
||||||
bool result;
|
bool result;
|
||||||
|
initShaders();
|
||||||
|
|
||||||
// We have no bootanimation file, so we use the stock android logo
|
// We have no bootanimation file, so we use the stock android logo
|
||||||
// animation.
|
// animation.
|
||||||
if (mZipFileName.isEmpty()) {
|
if (mZipFileName.isEmpty()) {
|
||||||
@ -623,6 +782,8 @@ bool BootAnimation::threadLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BootAnimation::android() {
|
bool BootAnimation::android() {
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
|
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
|
||||||
elapsedRealtime());
|
elapsedRealtime());
|
||||||
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
|
initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
|
||||||
@ -631,19 +792,16 @@ bool BootAnimation::android() {
|
|||||||
mCallbacks->init({});
|
mCallbacks->init({});
|
||||||
|
|
||||||
// clear screen
|
// clear screen
|
||||||
glShadeModel(GL_FLAT);
|
|
||||||
glDisable(GL_DITHER);
|
glDisable(GL_DITHER);
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
glUseProgram(mImageShader);
|
||||||
|
|
||||||
glClearColor(0,0,0,1);
|
glClearColor(0,0,0,1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
eglSwapBuffers(mDisplay, mSurface);
|
eglSwapBuffers(mDisplay, mSurface);
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
|
|
||||||
// Blend state
|
// Blend state
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
|
|
||||||
const nsecs_t startTime = systemTime();
|
const nsecs_t startTime = systemTime();
|
||||||
do {
|
do {
|
||||||
@ -666,12 +824,12 @@ bool BootAnimation::android() {
|
|||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
|
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
|
||||||
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
|
drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h);
|
||||||
glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
|
drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
|
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
|
||||||
glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
|
drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
|
||||||
|
|
||||||
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
|
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
|
||||||
if (res == EGL_FALSE)
|
if (res == EGL_FALSE)
|
||||||
@ -766,6 +924,20 @@ static bool parseColor(const char str[7], float color[3]) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse a color represented as a signed decimal int string.
|
||||||
|
// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
|
||||||
|
// If the input color string is empty, set color with values in defaultColor.
|
||||||
|
static void parseColorDecimalString(const std::string& colorString,
|
||||||
|
float color[3], float defaultColor[3]) {
|
||||||
|
if (colorString == "") {
|
||||||
|
memcpy(color, defaultColor, sizeof(float) * 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int colorInt = atoi(colorString.c_str());
|
||||||
|
color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
|
||||||
|
color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
|
||||||
|
color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
|
||||||
|
}
|
||||||
|
|
||||||
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
|
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
|
||||||
ZipEntryRO entry = zip->findEntryByName(name);
|
ZipEntryRO entry = zip->findEntryByName(name);
|
||||||
@ -798,10 +970,10 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
|
|||||||
|
|
||||||
status = initTexture(font->map, &font->texture.w, &font->texture.h);
|
status = initTexture(font->map, &font->texture.w, &font->texture.h);
|
||||||
|
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
} else if (fallback != nullptr) {
|
} else if (fallback != nullptr) {
|
||||||
status = initTexture(&font->texture, mAssets, fallback);
|
status = initTexture(&font->texture, mAssets, fallback);
|
||||||
} else {
|
} else {
|
||||||
@ -816,40 +988,11 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth,
|
|
||||||
const int frameHeight, const Animation::Part& part,
|
|
||||||
const int fadedFramesCount) {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
// avoid creating a hole due to mixing result alpha with GL_REPLACE texture
|
|
||||||
glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
|
||||||
|
|
||||||
const float alpha = static_cast<float>(fadedFramesCount) / part.framesToFadeCount;
|
|
||||||
glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha);
|
|
||||||
|
|
||||||
const float frameStartX = static_cast<float>(frameLeft);
|
|
||||||
const float frameStartY = static_cast<float>(frameBottom);
|
|
||||||
const float frameEndX = frameStartX + frameWidth;
|
|
||||||
const float frameEndY = frameStartY + frameHeight;
|
|
||||||
const GLfloat frameRect[] = {
|
|
||||||
frameStartX, frameStartY,
|
|
||||||
frameEndX, frameStartY,
|
|
||||||
frameEndX, frameEndY,
|
|
||||||
frameStartX, frameEndY
|
|
||||||
};
|
|
||||||
glVertexPointer(2, GL_FLOAT, 0, frameRect);
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
|
void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
|
||||||
glEnable(GL_BLEND); // Allow us to draw on top of the animation
|
glEnable(GL_BLEND); // Allow us to draw on top of the animation
|
||||||
glBindTexture(GL_TEXTURE_2D, font.texture.name);
|
glBindTexture(GL_TEXTURE_2D, font.texture.name);
|
||||||
|
glUseProgram(mTextShader);
|
||||||
|
glUniform1i(mTextTextureLocation, 0);
|
||||||
|
|
||||||
const int len = strlen(str);
|
const int len = strlen(str);
|
||||||
const int strWidth = font.char_width * len;
|
const int strWidth = font.char_width * len;
|
||||||
@ -865,8 +1008,6 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int*
|
|||||||
*y = mHeight + *y - font.char_height;
|
*y = mHeight + *y - font.char_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
|
|
||||||
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
char c = str[i];
|
char c = str[i];
|
||||||
|
|
||||||
@ -878,13 +1019,13 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int*
|
|||||||
const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters
|
const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters
|
||||||
const int row = charPos / FONT_NUM_COLS;
|
const int row = charPos / FONT_NUM_COLS;
|
||||||
const int col = charPos % FONT_NUM_COLS;
|
const int col = charPos % FONT_NUM_COLS;
|
||||||
cropRect[0] = col * font.char_width; // Left of column
|
// Bold fonts are expected in the second half of each row.
|
||||||
cropRect[1] = row * font.char_height * 2; // Top of row
|
float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS;
|
||||||
// Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
|
float u0 = ((float)col) / FONT_NUM_COLS;
|
||||||
cropRect[1] += bold ? 2 * font.char_height : font.char_height;
|
float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
|
||||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
|
float u1 = u0 + 1.0f / FONT_NUM_COLS;
|
||||||
|
glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
|
||||||
glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
|
drawTexturedQuad(*x, *y, font.char_width, font.char_height);
|
||||||
|
|
||||||
*x += font.char_width;
|
*x += font.char_width;
|
||||||
}
|
}
|
||||||
@ -938,6 +1079,8 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char const* s = desString.string();
|
char const* s = desString.string();
|
||||||
|
std::string dynamicColoringPartName = "";
|
||||||
|
bool postDynamicColoring = false;
|
||||||
|
|
||||||
// Parse the description file
|
// Parse the description file
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -952,11 +1095,19 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
|
|||||||
int pause = 0;
|
int pause = 0;
|
||||||
int progress = 0;
|
int progress = 0;
|
||||||
int framesToFadeCount = 0;
|
int framesToFadeCount = 0;
|
||||||
|
int colorTransitionStart = 0;
|
||||||
|
int colorTransitionEnd = 0;
|
||||||
char path[ANIM_ENTRY_NAME_MAX];
|
char path[ANIM_ENTRY_NAME_MAX];
|
||||||
char color[7] = "000000"; // default to black if unspecified
|
char color[7] = "000000"; // default to black if unspecified
|
||||||
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
|
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
|
||||||
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
|
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
|
||||||
|
char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
|
||||||
char pathType;
|
char pathType;
|
||||||
|
// start colors default to black if unspecified
|
||||||
|
char start_color_0[7] = "000000";
|
||||||
|
char start_color_1[7] = "000000";
|
||||||
|
char start_color_2[7] = "000000";
|
||||||
|
char start_color_3[7] = "000000";
|
||||||
|
|
||||||
int nextReadPos;
|
int nextReadPos;
|
||||||
|
|
||||||
@ -971,6 +1122,18 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
|
|||||||
} else {
|
} else {
|
||||||
animation.progressEnabled = false;
|
animation.progressEnabled = false;
|
||||||
}
|
}
|
||||||
|
} else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s %d %d",
|
||||||
|
dynamicColoringPartNameBuffer,
|
||||||
|
start_color_0, start_color_1, start_color_2, start_color_3,
|
||||||
|
&colorTransitionStart, &colorTransitionEnd)) {
|
||||||
|
animation.dynamicColoringEnabled = true;
|
||||||
|
parseColor(start_color_0, animation.startColors[0]);
|
||||||
|
parseColor(start_color_1, animation.startColors[1]);
|
||||||
|
parseColor(start_color_2, animation.startColors[2]);
|
||||||
|
parseColor(start_color_3, animation.startColors[3]);
|
||||||
|
animation.colorTransitionStart = colorTransitionStart;
|
||||||
|
animation.colorTransitionEnd = colorTransitionEnd;
|
||||||
|
dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
|
||||||
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
|
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
|
||||||
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
|
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
|
||||||
if (pathType == 'f') {
|
if (pathType == 'f') {
|
||||||
@ -983,6 +1146,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
|
|||||||
// "clockPos1=%s, clockPos2=%s",
|
// "clockPos1=%s, clockPos2=%s",
|
||||||
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
|
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
|
||||||
Animation::Part part;
|
Animation::Part part;
|
||||||
|
if (path == dynamicColoringPartName) {
|
||||||
|
// Part is specified to use dynamic coloring.
|
||||||
|
part.useDynamicColoring = true;
|
||||||
|
part.postDynamicColoring = false;
|
||||||
|
postDynamicColoring = true;
|
||||||
|
} else {
|
||||||
|
// Part does not use dynamic coloring.
|
||||||
|
part.useDynamicColoring = false;
|
||||||
|
part.postDynamicColoring = postDynamicColoring;
|
||||||
|
}
|
||||||
part.playUntilComplete = pathType == 'c';
|
part.playUntilComplete = pathType == 'c';
|
||||||
part.framesToFadeCount = framesToFadeCount;
|
part.framesToFadeCount = framesToFadeCount;
|
||||||
part.count = count;
|
part.count = count;
|
||||||
@ -1166,19 +1339,16 @@ bool BootAnimation::movie() {
|
|||||||
|
|
||||||
// Blend required to draw time on top of animation frames.
|
// Blend required to draw time on top of animation frames.
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glShadeModel(GL_FLAT);
|
|
||||||
glDisable(GL_DITHER);
|
glDisable(GL_DITHER);
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
bool clockFontInitialized = false;
|
bool clockFontInitialized = false;
|
||||||
if (mClockEnabled) {
|
if (mClockEnabled) {
|
||||||
clockFontInitialized =
|
clockFontInitialized =
|
||||||
@ -1193,6 +1363,10 @@ bool BootAnimation::movie() {
|
|||||||
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
|
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) {
|
||||||
|
initDynamicColors();
|
||||||
|
}
|
||||||
|
|
||||||
playAnimation(*mAnimation);
|
playAnimation(*mAnimation);
|
||||||
|
|
||||||
if (mTimeCheckThread != nullptr) {
|
if (mTimeCheckThread != nullptr) {
|
||||||
@ -1218,6 +1392,55 @@ bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part,
|
|||||||
(lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
|
(lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Linear mapping from range <a1, a2> to range <b1, b2>
|
||||||
|
float mapLinear(float x, float a1, float a2, float b1, float b2) {
|
||||||
|
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
|
||||||
|
// Map coordinates from screen space to world space.
|
||||||
|
float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
|
||||||
|
float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
|
||||||
|
float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1);
|
||||||
|
float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1);
|
||||||
|
// Update quad vertex positions.
|
||||||
|
quadPositions[0] = x0;
|
||||||
|
quadPositions[1] = y0;
|
||||||
|
quadPositions[2] = x1;
|
||||||
|
quadPositions[3] = y0;
|
||||||
|
quadPositions[4] = x1;
|
||||||
|
quadPositions[5] = y1;
|
||||||
|
quadPositions[6] = x1;
|
||||||
|
quadPositions[7] = y1;
|
||||||
|
quadPositions[8] = x0;
|
||||||
|
quadPositions[9] = y1;
|
||||||
|
quadPositions[10] = x0;
|
||||||
|
quadPositions[11] = y0;
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0,
|
||||||
|
sizeof(quadPositions) / sizeof(quadPositions[0]) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BootAnimation::initDynamicColors() {
|
||||||
|
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
|
||||||
|
parseColorDecimalString(
|
||||||
|
android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
|
||||||
|
mAnimation->endColors[i], mAnimation->startColors[i]);
|
||||||
|
}
|
||||||
|
glUseProgram(mImageShader);
|
||||||
|
SLOGI("[BootAnimation] Dynamically coloring boot animation.");
|
||||||
|
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
|
||||||
|
float *startColor = mAnimation->startColors[i];
|
||||||
|
float *endColor = mAnimation->endColors[i];
|
||||||
|
glUniform4f(glGetUniformLocation(mImageShader,
|
||||||
|
(U_START_COLOR_PREFIX + std::to_string(i)).c_str()),
|
||||||
|
startColor[0], startColor[1], startColor[2], 1 /* alpha */);
|
||||||
|
glUniform4f(glGetUniformLocation(mImageShader,
|
||||||
|
(U_END_COLOR_PREFIX + std::to_string(i)).c_str()),
|
||||||
|
endColor[0], endColor[1], endColor[2], 1 /* alpha */);
|
||||||
|
}
|
||||||
|
mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS);
|
||||||
|
}
|
||||||
|
|
||||||
bool BootAnimation::playAnimation(const Animation& animation) {
|
bool BootAnimation::playAnimation(const Animation& animation) {
|
||||||
const size_t pcount = animation.parts.size();
|
const size_t pcount = animation.parts.size();
|
||||||
nsecs_t frameDuration = s2ns(1) / animation.fps;
|
nsecs_t frameDuration = s2ns(1) / animation.fps;
|
||||||
@ -1230,7 +1453,6 @@ bool BootAnimation::playAnimation(const Animation& animation) {
|
|||||||
for (size_t i=0 ; i<pcount ; i++) {
|
for (size_t i=0 ; i<pcount ; i++) {
|
||||||
const Animation::Part& part(animation.parts[i]);
|
const Animation::Part& part(animation.parts[i]);
|
||||||
const size_t fcount = part.frames.size();
|
const size_t fcount = part.frames.size();
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
// Handle animation package
|
// Handle animation package
|
||||||
if (part.animation != nullptr) {
|
if (part.animation != nullptr) {
|
||||||
@ -1261,6 +1483,19 @@ bool BootAnimation::playAnimation(const Animation& animation) {
|
|||||||
for (size_t j=0 ; j<fcount ; j++) {
|
for (size_t j=0 ; j<fcount ; j++) {
|
||||||
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
|
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
|
||||||
|
|
||||||
|
// Color progress is
|
||||||
|
// - the animation progress, normalized from
|
||||||
|
// [colorTransitionStart,colorTransitionEnd] to [0, 1] for the dynamic coloring
|
||||||
|
// part.
|
||||||
|
// - 0 for parts that come before,
|
||||||
|
// - 1 for parts that come after.
|
||||||
|
float colorProgress = part.useDynamicColoring
|
||||||
|
? fmin(fmax(
|
||||||
|
((float)j - animation.colorTransitionStart) /
|
||||||
|
fmax(animation.colorTransitionEnd -
|
||||||
|
animation.colorTransitionStart, 1.0f), 0.0f), 1.0f)
|
||||||
|
: (part.postDynamicColoring ? 1 : 0);
|
||||||
|
|
||||||
processDisplayEvents();
|
processDisplayEvents();
|
||||||
|
|
||||||
const int animationX = (mWidth - animation.width) / 2;
|
const int animationX = (mWidth - animation.width) / 2;
|
||||||
@ -1272,44 +1507,38 @@ bool BootAnimation::playAnimation(const Animation& animation) {
|
|||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
glBindTexture(GL_TEXTURE_2D, frame.tid);
|
glBindTexture(GL_TEXTURE_2D, frame.tid);
|
||||||
} else {
|
} else {
|
||||||
if (part.count != 1) {
|
glGenTextures(1, &frame.tid);
|
||||||
glGenTextures(1, &frame.tid);
|
glBindTexture(GL_TEXTURE_2D, frame.tid);
|
||||||
glBindTexture(GL_TEXTURE_2D, frame.tid);
|
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
}
|
|
||||||
int w, h;
|
int w, h;
|
||||||
initTexture(frame.map, &w, &h);
|
// Set decoding option to alpha unpremultiplied so that the R, G, B channels
|
||||||
|
// of transparent pixels are preserved.
|
||||||
|
initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int xc = animationX + frame.trimX;
|
const int xc = animationX + frame.trimX;
|
||||||
const int yc = animationY + frame.trimY;
|
const int yc = animationY + frame.trimY;
|
||||||
Region clearReg(Rect(mWidth, mHeight));
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
|
|
||||||
if (!clearReg.isEmpty()) {
|
|
||||||
Region::const_iterator head(clearReg.begin());
|
|
||||||
Region::const_iterator tail(clearReg.end());
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
while (head != tail) {
|
|
||||||
const Rect& r2(*head++);
|
|
||||||
glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
}
|
|
||||||
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
|
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
|
||||||
// which is equivalent to mHeight - (yc + frame.trimHeight)
|
// which is equivalent to mHeight - (yc + frame.trimHeight)
|
||||||
const int frameDrawY = mHeight - (yc + frame.trimHeight);
|
const int frameDrawY = mHeight - (yc + frame.trimHeight);
|
||||||
glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
|
|
||||||
|
|
||||||
|
float fade = 0;
|
||||||
// if the part hasn't been stopped yet then continue fading if necessary
|
// if the part hasn't been stopped yet then continue fading if necessary
|
||||||
if (exitPending() && part.hasFadingPhase()) {
|
if (exitPending() && part.hasFadingPhase()) {
|
||||||
fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
|
fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount;
|
||||||
++fadedFramesCount);
|
|
||||||
if (fadedFramesCount >= part.framesToFadeCount) {
|
if (fadedFramesCount >= part.framesToFadeCount) {
|
||||||
fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
|
fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
glUseProgram(mImageShader);
|
||||||
|
glUniform1i(mImageTextureLocation, 0);
|
||||||
|
glUniform1f(mImageFadeLocation, fade);
|
||||||
|
if (animation.dynamicColoringEnabled) {
|
||||||
|
glUniform1f(mImageColorProgressLocation, colorProgress);
|
||||||
|
}
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
|
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
|
||||||
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
|
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include <binder/IBinder.h>
|
#include <binder/IBinder.h>
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <GLES/gl.h>
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Font {
|
struct Font {
|
||||||
FileMap* map;
|
FileMap* map = nullptr;
|
||||||
Texture texture;
|
Texture texture;
|
||||||
int char_width;
|
int char_width;
|
||||||
int char_height;
|
int char_height;
|
||||||
@ -62,7 +62,7 @@ public:
|
|||||||
struct Animation {
|
struct Animation {
|
||||||
struct Frame {
|
struct Frame {
|
||||||
String8 name;
|
String8 name;
|
||||||
FileMap* map;
|
FileMap* map = nullptr;
|
||||||
int trimX;
|
int trimX;
|
||||||
int trimY;
|
int trimY;
|
||||||
int trimWidth;
|
int trimWidth;
|
||||||
@ -90,6 +90,10 @@ public:
|
|||||||
uint8_t* audioData;
|
uint8_t* audioData;
|
||||||
int audioLength;
|
int audioLength;
|
||||||
Animation* animation;
|
Animation* animation;
|
||||||
|
// Controls if dynamic coloring is enabled for this part.
|
||||||
|
bool useDynamicColoring = false;
|
||||||
|
// Defines if this part is played after the dynamic coloring part.
|
||||||
|
bool postDynamicColoring = false;
|
||||||
|
|
||||||
bool hasFadingPhase() const {
|
bool hasFadingPhase() const {
|
||||||
return !playUntilComplete && framesToFadeCount > 0;
|
return !playUntilComplete && framesToFadeCount > 0;
|
||||||
@ -105,6 +109,12 @@ public:
|
|||||||
ZipFileRO* zip;
|
ZipFileRO* zip;
|
||||||
Font clockFont;
|
Font clockFont;
|
||||||
Font progressFont;
|
Font progressFont;
|
||||||
|
// Controls if dynamic coloring is enabled for the whole animation.
|
||||||
|
bool dynamicColoringEnabled = false;
|
||||||
|
int colorTransitionStart = 0; // Start frame of dynamic color transition.
|
||||||
|
int colorTransitionEnd = 0; // End frame of dynamic color transition.
|
||||||
|
float startColors[4][3]; // Start colors of dynamic color transition.
|
||||||
|
float endColors[4][3]; // End colors of dynamic color transition.
|
||||||
};
|
};
|
||||||
|
|
||||||
// All callbacks will be called from this class's internal thread.
|
// All callbacks will be called from this class's internal thread.
|
||||||
@ -163,9 +173,12 @@ private:
|
|||||||
int displayEventCallback(int fd, int events, void* data);
|
int displayEventCallback(int fd, int events, void* data);
|
||||||
void processDisplayEvents();
|
void processDisplayEvents();
|
||||||
|
|
||||||
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
|
status_t initTexture(Texture* texture, AssetManager& asset, const char* name,
|
||||||
status_t initTexture(FileMap* map, int* width, int* height);
|
bool premultiplyAlpha = true);
|
||||||
|
status_t initTexture(FileMap* map, int* width, int* height,
|
||||||
|
bool premultiplyAlpha = true);
|
||||||
status_t initFont(Font* font, const char* fallback);
|
status_t initFont(Font* font, const char* fallback);
|
||||||
|
void initShaders();
|
||||||
bool android();
|
bool android();
|
||||||
bool movie();
|
bool movie();
|
||||||
void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
|
void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
|
||||||
@ -173,6 +186,7 @@ private:
|
|||||||
void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
|
void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
|
||||||
void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
|
void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
|
||||||
const Animation::Part& part, int fadedFramesCount);
|
const Animation::Part& part, int fadedFramesCount);
|
||||||
|
void drawTexturedQuad(float xStart, float yStart, float width, float height);
|
||||||
bool validClock(const Animation::Part& part);
|
bool validClock(const Animation::Part& part);
|
||||||
Animation* loadAnimation(const String8&);
|
Animation* loadAnimation(const String8&);
|
||||||
bool playAnimation(const Animation&);
|
bool playAnimation(const Animation&);
|
||||||
@ -192,6 +206,7 @@ private:
|
|||||||
void checkExit();
|
void checkExit();
|
||||||
|
|
||||||
void handleViewport(nsecs_t timestep);
|
void handleViewport(nsecs_t timestep);
|
||||||
|
void initDynamicColors();
|
||||||
|
|
||||||
sp<SurfaceComposerClient> mSession;
|
sp<SurfaceComposerClient> mSession;
|
||||||
AssetManager mAssets;
|
AssetManager mAssets;
|
||||||
@ -218,6 +233,13 @@ private:
|
|||||||
sp<TimeCheckThread> mTimeCheckThread = nullptr;
|
sp<TimeCheckThread> mTimeCheckThread = nullptr;
|
||||||
sp<Callbacks> mCallbacks;
|
sp<Callbacks> mCallbacks;
|
||||||
Animation* mAnimation = nullptr;
|
Animation* mAnimation = nullptr;
|
||||||
|
GLuint mImageShader;
|
||||||
|
GLuint mTextShader;
|
||||||
|
GLuint mImageFadeLocation;
|
||||||
|
GLuint mImageTextureLocation;
|
||||||
|
GLuint mTextCropAreaLocation;
|
||||||
|
GLuint mTextTextureLocation;
|
||||||
|
GLuint mImageColorProgressLocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
set noparent
|
set noparent
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
zyy@google.com
|
zyy@google.com
|
||||||
|
@ -771,6 +771,11 @@ public class ActivityManager {
|
|||||||
return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
|
return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @hide Should this process state be considered in the cache? */
|
||||||
|
public static final boolean isProcStateCached(int procState) {
|
||||||
|
return procState >= PROCESS_STATE_CACHED_ACTIVITY;
|
||||||
|
}
|
||||||
|
|
||||||
/** @hide Is this a foreground service type? */
|
/** @hide Is this a foreground service type? */
|
||||||
public static boolean isForegroundService(int procState) {
|
public static boolean isForegroundService(int procState) {
|
||||||
return procState == PROCESS_STATE_FOREGROUND_SERVICE;
|
return procState == PROCESS_STATE_FOREGROUND_SERVICE;
|
||||||
|
@ -156,6 +156,7 @@ public abstract class ActivityManagerInternal {
|
|||||||
/**
|
/**
|
||||||
* Update information about which app IDs are on the temp allowlist.
|
* Update information about which app IDs are on the temp allowlist.
|
||||||
* @param appids the updated list of appIds in temp allowlist.
|
* @param appids the updated list of appIds in temp allowlist.
|
||||||
|
* If null, it is to update only changingUid.
|
||||||
* @param changingUid uid to add or remove to temp allowlist.
|
* @param changingUid uid to add or remove to temp allowlist.
|
||||||
* @param adding true to add to temp allowlist, false to remove from temp allowlist.
|
* @param adding true to add to temp allowlist, false to remove from temp allowlist.
|
||||||
* @param durationMs when adding is true, the duration to be in temp allowlist.
|
* @param durationMs when adding is true, the duration to be in temp allowlist.
|
||||||
@ -165,7 +166,7 @@ public abstract class ActivityManagerInternal {
|
|||||||
* @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
|
* @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
|
||||||
* is true.
|
* is true.
|
||||||
*/
|
*/
|
||||||
public abstract void updateDeviceIdleTempAllowlist(int[] appids, int changingUid,
|
public abstract void updateDeviceIdleTempAllowlist(@Nullable int[] appids, int changingUid,
|
||||||
boolean adding, long durationMs, @TempAllowListType int type,
|
boolean adding, long durationMs, @TempAllowListType int type,
|
||||||
@ReasonCode int reasonCode,
|
@ReasonCode int reasonCode,
|
||||||
@Nullable String reason, int callingUid);
|
@Nullable String reason, int callingUid);
|
||||||
|
@ -4906,7 +4906,8 @@ public final class ActivityThread extends ClientTransactionHandler
|
|||||||
Slog.w(TAG, "Activity top position already set to onTop=" + onTop);
|
Slog.w(TAG, "Activity top position already set to onTop=" + onTop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Activity top position already set to onTop=" + onTop);
|
// TODO(b/197484331): Remove this short-term workaround while fixing the binder failure.
|
||||||
|
Slog.e(TAG, "Activity top position already set to onTop=" + onTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
r.isTopResumedActivity = onTop;
|
r.isTopResumedActivity = onTop;
|
||||||
|
@ -2735,10 +2735,13 @@ class ContextImpl extends Context {
|
|||||||
// need to override their display in ResourcesManager.
|
// need to override their display in ResourcesManager.
|
||||||
baseContext.mForceDisplayOverrideInResources = false;
|
baseContext.mForceDisplayOverrideInResources = false;
|
||||||
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
|
baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
|
||||||
baseContext.mDisplay = display;
|
|
||||||
|
|
||||||
final Resources windowContextResources = createWindowContextResources(baseContext);
|
final Resources windowContextResources = createWindowContextResources(baseContext);
|
||||||
baseContext.setResources(windowContextResources);
|
baseContext.setResources(windowContextResources);
|
||||||
|
// Associate the display with window context resources so that configuration update from
|
||||||
|
// the server side will also apply to the display's metrics.
|
||||||
|
baseContext.mDisplay = ResourcesManager.getInstance()
|
||||||
|
.getAdjustedDisplay(display.getDisplayId(), windowContextResources);
|
||||||
|
|
||||||
return baseContext;
|
return baseContext;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,7 @@ public final class GameManager {
|
|||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of supported game modes for a given package.
|
* Returns a list of supported game modes for a given package.
|
||||||
* <p>
|
* <p>
|
||||||
@ -151,4 +152,20 @@ public final class GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if ANGLE is enabled for a given package.
|
||||||
|
* <p>
|
||||||
|
* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@UserHandleAware
|
||||||
|
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
|
||||||
|
public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
|
||||||
|
try {
|
||||||
|
return mService.getAngleEnabled(packageName, mContext.getUserId());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,5 @@ interface IGameManagerService {
|
|||||||
int getGameMode(String packageName, int userId);
|
int getGameMode(String packageName, int userId);
|
||||||
void setGameMode(String packageName, int gameMode, int userId);
|
void setGameMode(String packageName, int gameMode, int userId);
|
||||||
int[] getAvailableGameModes(String packageName);
|
int[] getAvailableGameModes(String packageName);
|
||||||
|
boolean getAngleEnabled(String packageName, int userId);
|
||||||
}
|
}
|
@ -1884,6 +1884,14 @@ public class Notification implements Parcelable
|
|||||||
* clicks. To launch an activity in those cases, provide a {@link PendingIntent} for the
|
* clicks. To launch an activity in those cases, provide a {@link PendingIntent} for the
|
||||||
* activity itself.
|
* activity itself.
|
||||||
*
|
*
|
||||||
|
* <p>How an Action is displayed, including whether the {@code icon}, {@code text}, or
|
||||||
|
* both are displayed or required, depends on where and how the action is used, and the
|
||||||
|
* {@link Style} applied to the Notification.
|
||||||
|
*
|
||||||
|
* <p>When the {@code title} is a {@link android.text.Spanned}, any colors set by a
|
||||||
|
* {@link ForegroundColorSpan} or {@link TextAppearanceSpan} may be removed or displayed
|
||||||
|
* with an altered in luminance to ensure proper contrast within the Notification.
|
||||||
|
*
|
||||||
* @param icon icon to show for this action
|
* @param icon icon to show for this action
|
||||||
* @param title the title of the action
|
* @param title the title of the action
|
||||||
* @param intent the {@link PendingIntent} to fire when users trigger this action
|
* @param intent the {@link PendingIntent} to fire when users trigger this action
|
||||||
@ -5387,8 +5395,8 @@ public class Notification implements Parcelable
|
|||||||
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
|
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
|
||||||
// Use different highlighted colors for conversations' unread count
|
// Use different highlighted colors for conversations' unread count
|
||||||
if (p.mHighlightExpander) {
|
if (p.mHighlightExpander) {
|
||||||
pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor);
|
pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
|
||||||
textColor = Colors.flattenAlpha(bgColor, pillColor);
|
textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor);
|
||||||
}
|
}
|
||||||
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
|
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
|
||||||
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
|
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
|
||||||
@ -6121,21 +6129,22 @@ public class Notification implements Parcelable
|
|||||||
if (emphasizedMode) {
|
if (emphasizedMode) {
|
||||||
// change the background bgColor
|
// change the background bgColor
|
||||||
CharSequence title = action.title;
|
CharSequence title = action.title;
|
||||||
ColorStateList[] outResultColor = new ColorStateList[1];
|
|
||||||
int buttonFillColor = getColors(p).getSecondaryAccentColor();
|
int buttonFillColor = getColors(p).getSecondaryAccentColor();
|
||||||
if (isLegacy()) {
|
if (isLegacy()) {
|
||||||
title = ContrastColorUtil.clearColorSpans(title);
|
title = ContrastColorUtil.clearColorSpans(title);
|
||||||
} else {
|
} else {
|
||||||
int notifBackgroundColor = getColors(p).getBackgroundColor();
|
// Check for a full-length span color to use as the button fill color.
|
||||||
title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor);
|
Integer fullLengthColor = getFullLengthSpanColor(title);
|
||||||
|
if (fullLengthColor != null) {
|
||||||
|
// Ensure the custom button fill has 1.3:1 contrast w/ notification bg.
|
||||||
|
int notifBackgroundColor = getColors(p).getBackgroundColor();
|
||||||
|
buttonFillColor = ensureButtonFillContrast(
|
||||||
|
fullLengthColor, notifBackgroundColor);
|
||||||
|
}
|
||||||
|
// Remove full-length color spans and ensure text contrast with the button fill.
|
||||||
|
title = ensureColorSpanContrast(title, buttonFillColor);
|
||||||
}
|
}
|
||||||
button.setTextViewText(R.id.action0, processTextSpans(title));
|
button.setTextViewText(R.id.action0, processTextSpans(title));
|
||||||
boolean hasColorOverride = outResultColor[0] != null;
|
|
||||||
if (hasColorOverride) {
|
|
||||||
// There's a span spanning the full text, let's take it and use it as the
|
|
||||||
// background color
|
|
||||||
buttonFillColor = outResultColor[0].getDefaultColor();
|
|
||||||
}
|
|
||||||
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
|
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
|
||||||
buttonFillColor, mInNightMode);
|
buttonFillColor, mInNightMode);
|
||||||
button.setTextColor(R.id.action0, textColor);
|
button.setTextColor(R.id.action0, textColor);
|
||||||
@ -6168,17 +6177,58 @@ public class Notification implements Parcelable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures contrast on color spans against a background color. also returns the color of the
|
* Extract the color from a full-length span from the text.
|
||||||
* text if a span was found that spans over the whole text.
|
*
|
||||||
|
* @param charSequence the charSequence containing spans
|
||||||
|
* @return the raw color of the text's last full-length span containing a color, or null if
|
||||||
|
* no full-length span sets the text color.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
@Nullable
|
||||||
|
public static Integer getFullLengthSpanColor(CharSequence charSequence) {
|
||||||
|
// NOTE: this method preserves the functionality that for a CharSequence with multiple
|
||||||
|
// full-length spans, the color of the last one is used.
|
||||||
|
Integer result = null;
|
||||||
|
if (charSequence instanceof Spanned) {
|
||||||
|
Spanned ss = (Spanned) charSequence;
|
||||||
|
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
|
||||||
|
// First read through all full-length spans to get the button fill color, which will
|
||||||
|
// be used as the background color for ensuring contrast of non-full-length spans.
|
||||||
|
for (Object span : spans) {
|
||||||
|
int spanStart = ss.getSpanStart(span);
|
||||||
|
int spanEnd = ss.getSpanEnd(span);
|
||||||
|
boolean fullLength = (spanEnd - spanStart) == charSequence.length();
|
||||||
|
if (!fullLength) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (span instanceof TextAppearanceSpan) {
|
||||||
|
TextAppearanceSpan originalSpan = (TextAppearanceSpan) span;
|
||||||
|
ColorStateList textColor = originalSpan.getTextColor();
|
||||||
|
if (textColor != null) {
|
||||||
|
result = textColor.getDefaultColor();
|
||||||
|
}
|
||||||
|
} else if (span instanceof ForegroundColorSpan) {
|
||||||
|
ForegroundColorSpan originalSpan = (ForegroundColorSpan) span;
|
||||||
|
result = originalSpan.getForegroundColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures contrast on color spans against a background color.
|
||||||
|
* Note that any full-length color spans will be removed instead of being contrasted.
|
||||||
*
|
*
|
||||||
* @param charSequence the charSequence on which the spans are
|
* @param charSequence the charSequence on which the spans are
|
||||||
* @param background the background color to ensure the contrast against
|
* @param background the background color to ensure the contrast against
|
||||||
* @param outResultColor an array in which a color will be returned as the first element if
|
|
||||||
* there exists a full length color span.
|
|
||||||
* @return the contrasted charSequence
|
* @return the contrasted charSequence
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
private static CharSequence ensureColorSpanContrast(CharSequence charSequence,
|
@VisibleForTesting
|
||||||
int background, ColorStateList[] outResultColor) {
|
public static CharSequence ensureColorSpanContrast(CharSequence charSequence,
|
||||||
|
int background) {
|
||||||
if (charSequence instanceof Spanned) {
|
if (charSequence instanceof Spanned) {
|
||||||
Spanned ss = (Spanned) charSequence;
|
Spanned ss = (Spanned) charSequence;
|
||||||
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
|
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
|
||||||
@ -6195,19 +6245,19 @@ public class Notification implements Parcelable
|
|||||||
TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
|
TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
|
||||||
ColorStateList textColor = originalSpan.getTextColor();
|
ColorStateList textColor = originalSpan.getTextColor();
|
||||||
if (textColor != null) {
|
if (textColor != null) {
|
||||||
int[] colors = textColor.getColors();
|
|
||||||
int[] newColors = new int[colors.length];
|
|
||||||
for (int i = 0; i < newColors.length; i++) {
|
|
||||||
boolean isBgDark = isColorDark(background);
|
|
||||||
newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
|
|
||||||
colors[i], background, isBgDark);
|
|
||||||
}
|
|
||||||
textColor = new ColorStateList(textColor.getStates().clone(),
|
|
||||||
newColors);
|
|
||||||
if (fullLength) {
|
if (fullLength) {
|
||||||
outResultColor[0] = textColor;
|
|
||||||
// Let's drop the color from the span
|
// Let's drop the color from the span
|
||||||
textColor = null;
|
textColor = null;
|
||||||
|
} else {
|
||||||
|
int[] colors = textColor.getColors();
|
||||||
|
int[] newColors = new int[colors.length];
|
||||||
|
for (int i = 0; i < newColors.length; i++) {
|
||||||
|
boolean isBgDark = isColorDark(background);
|
||||||
|
newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
|
||||||
|
colors[i], background, isBgDark);
|
||||||
|
}
|
||||||
|
textColor = new ColorStateList(textColor.getStates().clone(),
|
||||||
|
newColors);
|
||||||
}
|
}
|
||||||
resultSpan = new TextAppearanceSpan(
|
resultSpan = new TextAppearanceSpan(
|
||||||
originalSpan.getFamily(),
|
originalSpan.getFamily(),
|
||||||
@ -6217,15 +6267,14 @@ public class Notification implements Parcelable
|
|||||||
originalSpan.getLinkTextColor());
|
originalSpan.getLinkTextColor());
|
||||||
}
|
}
|
||||||
} else if (resultSpan instanceof ForegroundColorSpan) {
|
} else if (resultSpan instanceof ForegroundColorSpan) {
|
||||||
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
|
|
||||||
int foregroundColor = originalSpan.getForegroundColor();
|
|
||||||
boolean isBgDark = isColorDark(background);
|
|
||||||
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
|
|
||||||
foregroundColor, background, isBgDark);
|
|
||||||
if (fullLength) {
|
if (fullLength) {
|
||||||
outResultColor[0] = ColorStateList.valueOf(foregroundColor);
|
|
||||||
resultSpan = null;
|
resultSpan = null;
|
||||||
} else {
|
} else {
|
||||||
|
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
|
||||||
|
int foregroundColor = originalSpan.getForegroundColor();
|
||||||
|
boolean isBgDark = isColorDark(background);
|
||||||
|
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
|
||||||
|
foregroundColor, background, isBgDark);
|
||||||
resultSpan = new ForegroundColorSpan(foregroundColor);
|
resultSpan = new ForegroundColorSpan(foregroundColor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -6247,12 +6296,28 @@ public class Notification implements Parcelable
|
|||||||
*
|
*
|
||||||
* @param color the color to check
|
* @param color the color to check
|
||||||
* @return true if the color has higher contrast with white than black
|
* @return true if the color has higher contrast with white than black
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
private static boolean isColorDark(int color) {
|
public static boolean isColorDark(int color) {
|
||||||
// as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
|
// as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
|
||||||
return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
|
return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a button fill color with sufficient contrast over bg (1.3:1) that has the same hue
|
||||||
|
* as the original color, but is lightened or darkened depending on whether the background
|
||||||
|
* is dark or light.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static int ensureButtonFillContrast(int color, int bg) {
|
||||||
|
return isColorDark(bg)
|
||||||
|
? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, 1.3)
|
||||||
|
: ContrastColorUtil.findContrastColor(color, bg, true, 1.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether we are currently building a notification from a legacy (an app that
|
* @return Whether we are currently building a notification from a legacy (an app that
|
||||||
* doesn't create material notifications by itself) app.
|
* doesn't create material notifications by itself) app.
|
||||||
@ -6441,25 +6506,34 @@ public class Notification implements Parcelable
|
|||||||
|
|
||||||
if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
|
if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
|
||||||
&& !styleDisplaysCustomViewInline()) {
|
&& !styleDisplaysCustomViewInline()) {
|
||||||
if (mN.contentView == null) {
|
RemoteViews newContentView = mN.contentView;
|
||||||
mN.contentView = createContentView();
|
RemoteViews newBigContentView = mN.bigContentView;
|
||||||
|
RemoteViews newHeadsUpContentView = mN.headsUpContentView;
|
||||||
|
if (newContentView == null) {
|
||||||
|
newContentView = createContentView();
|
||||||
mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
|
mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
|
||||||
mN.contentView.getSequenceNumber());
|
newContentView.getSequenceNumber());
|
||||||
}
|
}
|
||||||
if (mN.bigContentView == null) {
|
if (newBigContentView == null) {
|
||||||
mN.bigContentView = createBigContentView();
|
newBigContentView = createBigContentView();
|
||||||
if (mN.bigContentView != null) {
|
if (newBigContentView != null) {
|
||||||
mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
|
mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
|
||||||
mN.bigContentView.getSequenceNumber());
|
newBigContentView.getSequenceNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mN.headsUpContentView == null) {
|
if (newHeadsUpContentView == null) {
|
||||||
mN.headsUpContentView = createHeadsUpContentView();
|
newHeadsUpContentView = createHeadsUpContentView();
|
||||||
if (mN.headsUpContentView != null) {
|
if (newHeadsUpContentView != null) {
|
||||||
mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
|
mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
|
||||||
mN.headsUpContentView.getSequenceNumber());
|
newHeadsUpContentView.getSequenceNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Don't set any of the content views until after they have all been generated,
|
||||||
|
// to avoid the generated .contentView triggering the logic which skips generating
|
||||||
|
// the .bigContentView.
|
||||||
|
mN.contentView = newContentView;
|
||||||
|
mN.bigContentView = newBigContentView;
|
||||||
|
mN.headsUpContentView = newHeadsUpContentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
|
if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
|
||||||
@ -12305,6 +12379,8 @@ public class Notification implements Parcelable
|
|||||||
private int mSecondaryTextColor = COLOR_INVALID;
|
private int mSecondaryTextColor = COLOR_INVALID;
|
||||||
private int mPrimaryAccentColor = COLOR_INVALID;
|
private int mPrimaryAccentColor = COLOR_INVALID;
|
||||||
private int mSecondaryAccentColor = COLOR_INVALID;
|
private int mSecondaryAccentColor = COLOR_INVALID;
|
||||||
|
private int mTertiaryAccentColor = COLOR_INVALID;
|
||||||
|
private int mOnAccentTextColor = COLOR_INVALID;
|
||||||
private int mErrorColor = COLOR_INVALID;
|
private int mErrorColor = COLOR_INVALID;
|
||||||
private int mContrastColor = COLOR_INVALID;
|
private int mContrastColor = COLOR_INVALID;
|
||||||
private int mRippleAlpha = 0x33;
|
private int mRippleAlpha = 0x33;
|
||||||
@ -12362,7 +12438,7 @@ public class Notification implements Parcelable
|
|||||||
|
|
||||||
if (isColorized) {
|
if (isColorized) {
|
||||||
if (rawColor == COLOR_DEFAULT) {
|
if (rawColor == COLOR_DEFAULT) {
|
||||||
int[] attrs = {R.attr.colorAccentTertiary};
|
int[] attrs = {R.attr.colorAccentSecondary};
|
||||||
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
|
try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
|
||||||
mBackgroundColor = getColor(ta, 0, Color.WHITE);
|
mBackgroundColor = getColor(ta, 0, Color.WHITE);
|
||||||
}
|
}
|
||||||
@ -12379,6 +12455,8 @@ public class Notification implements Parcelable
|
|||||||
mContrastColor = mPrimaryTextColor;
|
mContrastColor = mPrimaryTextColor;
|
||||||
mPrimaryAccentColor = mPrimaryTextColor;
|
mPrimaryAccentColor = mPrimaryTextColor;
|
||||||
mSecondaryAccentColor = mSecondaryTextColor;
|
mSecondaryAccentColor = mSecondaryTextColor;
|
||||||
|
mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
|
||||||
|
mOnAccentTextColor = mBackgroundColor;
|
||||||
mErrorColor = mPrimaryTextColor;
|
mErrorColor = mPrimaryTextColor;
|
||||||
mRippleAlpha = 0x33;
|
mRippleAlpha = 0x33;
|
||||||
} else {
|
} else {
|
||||||
@ -12389,6 +12467,8 @@ public class Notification implements Parcelable
|
|||||||
R.attr.textColorSecondary,
|
R.attr.textColorSecondary,
|
||||||
R.attr.colorAccent,
|
R.attr.colorAccent,
|
||||||
R.attr.colorAccentSecondary,
|
R.attr.colorAccentSecondary,
|
||||||
|
R.attr.colorAccentTertiary,
|
||||||
|
R.attr.textColorOnAccent,
|
||||||
R.attr.colorError,
|
R.attr.colorError,
|
||||||
R.attr.colorControlHighlight
|
R.attr.colorControlHighlight
|
||||||
};
|
};
|
||||||
@ -12399,8 +12479,10 @@ public class Notification implements Parcelable
|
|||||||
mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
|
mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
|
||||||
mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
|
mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
|
||||||
mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
|
mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
|
||||||
mErrorColor = getColor(ta, 6, COLOR_INVALID);
|
mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID);
|
||||||
mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
|
mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID);
|
||||||
|
mErrorColor = getColor(ta, 8, COLOR_INVALID);
|
||||||
|
mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff));
|
||||||
}
|
}
|
||||||
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
|
mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
|
||||||
mBackgroundColor, nightMode);
|
mBackgroundColor, nightMode);
|
||||||
@ -12420,6 +12502,14 @@ public class Notification implements Parcelable
|
|||||||
if (mSecondaryAccentColor == COLOR_INVALID) {
|
if (mSecondaryAccentColor == COLOR_INVALID) {
|
||||||
mSecondaryAccentColor = mContrastColor;
|
mSecondaryAccentColor = mContrastColor;
|
||||||
}
|
}
|
||||||
|
if (mTertiaryAccentColor == COLOR_INVALID) {
|
||||||
|
mTertiaryAccentColor = mContrastColor;
|
||||||
|
}
|
||||||
|
if (mOnAccentTextColor == COLOR_INVALID) {
|
||||||
|
mOnAccentTextColor = ColorUtils.setAlphaComponent(
|
||||||
|
ContrastColorUtil.resolvePrimaryColor(
|
||||||
|
ctx, mTertiaryAccentColor, nightMode), 0xFF);
|
||||||
|
}
|
||||||
if (mErrorColor == COLOR_INVALID) {
|
if (mErrorColor == COLOR_INVALID) {
|
||||||
mErrorColor = mPrimaryTextColor;
|
mErrorColor = mPrimaryTextColor;
|
||||||
}
|
}
|
||||||
@ -12485,6 +12575,16 @@ public class Notification implements Parcelable
|
|||||||
return mSecondaryAccentColor;
|
return mSecondaryAccentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the theme's tertiary accent color for colored UI elements. */
|
||||||
|
public @ColorInt int getTertiaryAccentColor() {
|
||||||
|
return mTertiaryAccentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the theme's text color to be used on the tertiary accent color. */
|
||||||
|
public @ColorInt int getOnAccentTextColor() {
|
||||||
|
return mOnAccentTextColor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the contrast-adjusted version of the color provided by the app, or the
|
* @return the contrast-adjusted version of the color provided by the app, or the
|
||||||
* primary text color when colorized.
|
* primary text color when colorized.
|
||||||
|
@ -260,8 +260,6 @@ public final class NotificationChannel implements Parcelable {
|
|||||||
private boolean mDemoted = false;
|
private boolean mDemoted = false;
|
||||||
private boolean mImportantConvo = false;
|
private boolean mImportantConvo = false;
|
||||||
private long mDeletedTime = DEFAULT_DELETION_TIME_MS;
|
private long mDeletedTime = DEFAULT_DELETION_TIME_MS;
|
||||||
// If the sound for this channel is missing, e.g. after restore.
|
|
||||||
private boolean mIsSoundMissing;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a notification channel.
|
* Creates a notification channel.
|
||||||
@ -716,13 +714,6 @@ public final class NotificationChannel implements Parcelable {
|
|||||||
return mSound;
|
return mSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public boolean isSoundMissing() {
|
|
||||||
return mIsSoundMissing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the audio attributes for sound played by notifications posted to this channel.
|
* Returns the audio attributes for sound played by notifications posted to this channel.
|
||||||
*/
|
*/
|
||||||
@ -1007,9 +998,8 @@ public final class NotificationChannel implements Parcelable {
|
|||||||
// according to the docs because canonicalize method has to handle canonical uris as well.
|
// according to the docs because canonicalize method has to handle canonical uris as well.
|
||||||
Uri canonicalizedUri = contentResolver.canonicalize(uri);
|
Uri canonicalizedUri = contentResolver.canonicalize(uri);
|
||||||
if (canonicalizedUri == null) {
|
if (canonicalizedUri == null) {
|
||||||
// We got a null because the uri in the backup does not exist here.
|
// We got a null because the uri in the backup does not exist here, so we return default
|
||||||
mIsSoundMissing = true;
|
return Settings.System.DEFAULT_NOTIFICATION_URI;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return contentResolver.uncanonicalize(canonicalizedUri);
|
return contentResolver.uncanonicalize(canonicalizedUri);
|
||||||
}
|
}
|
||||||
|
@ -559,6 +559,53 @@ public class WallpaperManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rect peekWallpaperDimensions(Context context, boolean returnDefault, int userId) {
|
||||||
|
if (mService != null) {
|
||||||
|
try {
|
||||||
|
if (!mService.isWallpaperSupported(context.getOpPackageName())) {
|
||||||
|
return new Rect();
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect dimensions = null;
|
||||||
|
synchronized (this) {
|
||||||
|
try {
|
||||||
|
Bundle params = new Bundle();
|
||||||
|
// Let's peek user wallpaper first.
|
||||||
|
ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
|
||||||
|
context.getOpPackageName(), context.getAttributionTag(), this,
|
||||||
|
FLAG_SYSTEM, params, userId);
|
||||||
|
if (pfd != null) {
|
||||||
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
options.inJustDecodeBounds = true;
|
||||||
|
BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, options);
|
||||||
|
dimensions = new Rect(0, 0, options.outWidth, options.outHeight);
|
||||||
|
}
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
Log.w(TAG, "peek wallpaper dimensions failed", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If user wallpaper is unavailable, may be the default one instead.
|
||||||
|
if ((dimensions == null || dimensions.width() == 0 || dimensions.height() == 0)
|
||||||
|
&& returnDefault) {
|
||||||
|
InputStream is = openDefaultWallpaper(context, FLAG_SYSTEM);
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
options.inJustDecodeBounds = true;
|
||||||
|
BitmapFactory.decodeStream(is, null, options);
|
||||||
|
dimensions = new Rect(0, 0, options.outWidth, options.outHeight);
|
||||||
|
} finally {
|
||||||
|
IoUtils.closeQuietly(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
void forgetLoadedWallpaper() {
|
void forgetLoadedWallpaper() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mCachedWallpaper = null;
|
mCachedWallpaper = null;
|
||||||
@ -1038,6 +1085,17 @@ public class WallpaperManager {
|
|||||||
return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy);
|
return sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, userId, hardware, cmProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peek the dimensions of system wallpaper of the user without decoding it.
|
||||||
|
*
|
||||||
|
* @return the dimensions of system wallpaper
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public Rect peekBitmapDimensions() {
|
||||||
|
return sGlobals.peekWallpaperDimensions(
|
||||||
|
mContext, true /* returnDefault */, mContext.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an open, readable file descriptor to the given wallpaper image file.
|
* Get an open, readable file descriptor to the given wallpaper image file.
|
||||||
* The caller is responsible for closing the file descriptor when done ingesting the file.
|
* The caller is responsible for closing the file descriptor when done ingesting the file.
|
||||||
|
@ -9733,6 +9733,27 @@ public class DevicePolicyManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param userId The user for whom to retrieve information.
|
||||||
|
* @param restriction The restriction enforced by admin. It could be any user restriction or
|
||||||
|
* policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and
|
||||||
|
* {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}.
|
||||||
|
* @return Details of admin and user which enforced the restriction for the userId. If
|
||||||
|
* restriction is null, profile owner for the user or device owner info is returned.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public @Nullable Bundle getEnforcingAdminAndUserDetails(int userId,
|
||||||
|
@Nullable String restriction) {
|
||||||
|
if (mService != null) {
|
||||||
|
try {
|
||||||
|
return mService.getEnforcingAdminAndUserDetails(userId, restriction);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and
|
* Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and
|
||||||
* actual package file remain. This function can be called by a device owner, profile owner, or
|
* actual package file remain. This function can be called by a device owner, profile owner, or
|
||||||
|
@ -251,6 +251,7 @@ interface IDevicePolicyManager {
|
|||||||
boolean isNotificationListenerServicePermitted(in String packageName, int userId);
|
boolean isNotificationListenerServicePermitted(in String packageName, int userId);
|
||||||
|
|
||||||
Intent createAdminSupportIntent(in String restriction);
|
Intent createAdminSupportIntent(in String restriction);
|
||||||
|
Bundle getEnforcingAdminAndUserDetails(int userId,String restriction);
|
||||||
boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent);
|
boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent);
|
||||||
boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent);
|
boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent);
|
||||||
|
|
||||||
|
@ -280,6 +280,32 @@ public class BackupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for callers who need to indicate that some other package or
|
||||||
|
* some other user needs a backup pass. This can be useful in the case of groups of
|
||||||
|
* packages that share a uid and/or have user-specific data.
|
||||||
|
* <p>
|
||||||
|
* This method requires that the application hold the "android.permission.BACKUP"
|
||||||
|
* permission if the package named in the package argument does not run under the
|
||||||
|
* same uid as the caller. This method also requires that the application hold the
|
||||||
|
* "android.permission.INTERACT_ACROSS_USERS_FULL" if the user argument is not the
|
||||||
|
* same as the user the caller is running under.
|
||||||
|
* @param userId The user to back up
|
||||||
|
* @param packageName The package name identifying the application to back up.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static void dataChangedForUser(int userId, String packageName) {
|
||||||
|
checkServiceBinder();
|
||||||
|
if (sService != null) {
|
||||||
|
try {
|
||||||
|
sService.dataChangedForUser(userId, packageName);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "dataChanged(userId,pkg) couldn't connect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Applications shouldn't request a restore operation using this method. In Android
|
* @deprecated Applications shouldn't request a restore operation using this method. In Android
|
||||||
* P and later, this method is a no-op.
|
* P and later, this method is a no-op.
|
||||||
|
@ -70,7 +70,7 @@ public final class Query implements Parcelable {
|
|||||||
@NonNull Bundle extras) {
|
@NonNull Bundle extras) {
|
||||||
mInput = input;
|
mInput = input;
|
||||||
mTimestampMillis = timestampMillis;
|
mTimestampMillis = timestampMillis;
|
||||||
mExtras = extras == null ? extras : new Bundle();
|
mExtras = extras != null ? extras : new Bundle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,7 +143,7 @@ public class AppWidgetProviderInfo implements Parcelable {
|
|||||||
public ComponentName provider;
|
public ComponentName provider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default height of the widget when added to a host, in dp. The widget will get
|
* The default height of the widget when added to a host, in px. The widget will get
|
||||||
* at least this width, and will often be given more, depending on the host.
|
* at least this width, and will often be given more, depending on the host.
|
||||||
*
|
*
|
||||||
* <p>This field corresponds to the <code>android:minWidth</code> attribute in
|
* <p>This field corresponds to the <code>android:minWidth</code> attribute in
|
||||||
@ -152,7 +152,7 @@ public class AppWidgetProviderInfo implements Parcelable {
|
|||||||
public int minWidth;
|
public int minWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default height of the widget when added to a host, in dp. The widget will get
|
* The default height of the widget when added to a host, in px. The widget will get
|
||||||
* at least this height, and will often be given more, depending on the host.
|
* at least this height, and will often be given more, depending on the host.
|
||||||
*
|
*
|
||||||
* <p>This field corresponds to the <code>android:minHeight</code> attribute in
|
* <p>This field corresponds to the <code>android:minHeight</code> attribute in
|
||||||
@ -161,7 +161,7 @@ public class AppWidgetProviderInfo implements Parcelable {
|
|||||||
public int minHeight;
|
public int minHeight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimum width (in dp) which the widget can be resized to. This field has no effect if it
|
* Minimum width (in px) which the widget can be resized to. This field has no effect if it
|
||||||
* is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
|
* is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
|
||||||
*
|
*
|
||||||
* <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
|
* <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
|
||||||
@ -170,7 +170,7 @@ public class AppWidgetProviderInfo implements Parcelable {
|
|||||||
public int minResizeWidth;
|
public int minResizeWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimum height (in dp) which the widget can be resized to. This field has no effect if it
|
* Minimum height (in px) which the widget can be resized to. This field has no effect if it
|
||||||
* is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
|
* is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
|
||||||
*
|
*
|
||||||
* <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
|
* <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
|
||||||
@ -179,7 +179,7 @@ public class AppWidgetProviderInfo implements Parcelable {
|
|||||||
public int minResizeHeight;
|
public int minResizeHeight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum width (in dp) which the widget can be resized to. This field has no effect if it is
|
* Maximum width (in px) which the widget can be resized to. This field has no effect if it is
|
||||||
* smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
|
* smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
|
||||||
*
|
*
|
||||||
* <p>This field corresponds to the <code>android:maxResizeWidth</code> attribute in the
|
* <p>This field corresponds to the <code>android:maxResizeWidth</code> attribute in the
|
||||||
@ -189,7 +189,7 @@ public class AppWidgetProviderInfo implements Parcelable {
|
|||||||
public int maxResizeWidth;
|
public int maxResizeWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum height (in dp) which the widget can be resized to. This field has no effect if it is
|
* Maximum height (in px) which the widget can be resized to. This field has no effect if it is
|
||||||
* smaller than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
|
* smaller than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
|
||||||
*
|
*
|
||||||
* <p>This field corresponds to the <code>android:maxResizeHeight</code> attribute in the
|
* <p>This field corresponds to the <code>android:maxResizeHeight</code> attribute in the
|
||||||
|
@ -3286,7 +3286,7 @@ public abstract class Context {
|
|||||||
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O}
|
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O}
|
||||||
* or higher are not allowed to start background services from the background.
|
* or higher are not allowed to start background services from the background.
|
||||||
* See
|
* See
|
||||||
* <a href="{@docRoot}/about/versions/oreo/background">
|
* <a href="/about/versions/oreo/background">
|
||||||
* Background Execution Limits</a>
|
* Background Execution Limits</a>
|
||||||
* for more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
@ -3295,7 +3295,7 @@ public abstract class Context {
|
|||||||
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
|
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
|
||||||
* or higher are not allowed to start foreground services from the background.
|
* or higher are not allowed to start foreground services from the background.
|
||||||
* See
|
* See
|
||||||
* <a href="{@docRoot}/about/versions/12/behavior-changes-12">
|
* <a href="/about/versions/12/behavior-changes-12">
|
||||||
* Behavior changes: Apps targeting Android 12
|
* Behavior changes: Apps targeting Android 12
|
||||||
* </a>
|
* </a>
|
||||||
* for more details.
|
* for more details.
|
||||||
@ -3349,7 +3349,7 @@ public abstract class Context {
|
|||||||
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
|
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
|
||||||
* or higher are not allowed to start foreground services from the background.
|
* or higher are not allowed to start foreground services from the background.
|
||||||
* See
|
* See
|
||||||
* <a href="{@docRoot}/about/versions/12/behavior-changes-12">
|
* <a href="/about/versions/12/behavior-changes-12">
|
||||||
* Behavior changes: Apps targeting Android 12
|
* Behavior changes: Apps targeting Android 12
|
||||||
* </a>
|
* </a>
|
||||||
* for more details.
|
* for more details.
|
||||||
@ -6026,6 +6026,10 @@ public abstract class Context {
|
|||||||
* more general access to the URI's content provider then this check will
|
* more general access to the URI's content provider then this check will
|
||||||
* always fail.
|
* always fail.
|
||||||
*
|
*
|
||||||
|
* <strong>Note:</strong> On SDK Version {@link android.os.Build.VERSION_CODES#S},
|
||||||
|
* calling this method from a secondary-user's context will incorrectly return
|
||||||
|
* {@link PackageManager#PERMISSION_DENIED} for all {code uris}.
|
||||||
|
*
|
||||||
* @param uris The list of URIs that is being checked.
|
* @param uris The list of URIs that is being checked.
|
||||||
* @param pid The process ID being checked against. Must be > 0.
|
* @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
|
* @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)
|
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||||
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
|
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
|
||||||
|
/**
|
||||||
|
* Broadcast Action: One of the suspend conditions have been modified for the packages.
|
||||||
|
* <p>Includes the following extras:
|
||||||
|
* <ul>
|
||||||
|
* <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been modified
|
||||||
|
* <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been modified
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p class="note">This is a protected intent that can only be sent
|
||||||
|
* by the system. It is only sent to registered receivers.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||||
|
public static final String ACTION_PACKAGES_SUSPENSION_CHANGED =
|
||||||
|
"android.intent.action.PACKAGES_SUSPENSION_CHANGED";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast Action: Distracting packages have been changed.
|
* Broadcast Action: Distracting packages have been changed.
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# Bug component: 722021
|
# Bug component: 722021
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
# Bug component: 568631
|
# Bug component: 568631
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
zyy@google.com
|
zyy@google.com
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
# Bug component: 36137
|
# Bug component: 36137
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
|
|
||||||
per-file PackageParser.java = set noparent
|
per-file PackageParser.java = set noparent
|
||||||
per-file PackageParser.java = chiuwinson@google.com,patb@google.com,toddke@google.com
|
per-file PackageParser.java = chiuwinson@google.com,patb@google.com
|
||||||
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
|
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
|
||||||
per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
|
per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
|
||||||
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
|
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# Bug component: 86431
|
# Bug component: 86431
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
calin@google.com
|
calin@google.com
|
||||||
ngeoffray@google.com
|
ngeoffray@google.com
|
||||||
|
@ -2,4 +2,3 @@
|
|||||||
|
|
||||||
chiuwinson@google.com
|
chiuwinson@google.com
|
||||||
patb@google.com
|
patb@google.com
|
||||||
toddke@google.com
|
|
||||||
|
@ -2,7 +2,5 @@
|
|||||||
|
|
||||||
include platform/frameworks/base:/core/java/android/permission/OWNERS
|
include platform/frameworks/base:/core/java/android/permission/OWNERS
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# Bug component: 36137
|
# Bug component: 36137
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
|
@ -2,4 +2,3 @@
|
|||||||
|
|
||||||
chiuwinson@google.com
|
chiuwinson@google.com
|
||||||
patb@google.com
|
patb@google.com
|
||||||
toddke@google.com
|
|
@ -1,6 +1,4 @@
|
|||||||
# Bug component: 568761
|
# Bug component: 568761
|
||||||
|
|
||||||
toddke@android.com
|
|
||||||
toddke@google.com
|
|
||||||
patb@google.com
|
patb@google.com
|
||||||
zyy@google.com
|
zyy@google.com
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Camera
|
# Camera
|
||||||
per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com
|
per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com
|
||||||
|
|
||||||
# Sensor Privacy
|
# Sensor Privacy
|
||||||
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
|
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
|
||||||
|
@ -438,9 +438,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
|
private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
|
||||||
|
private final long mAuthRequestId;
|
||||||
|
|
||||||
|
OnAuthenticationCancelListener(long id) {
|
||||||
|
mAuthRequestId = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel() {
|
public void onCancel() {
|
||||||
cancelAuthentication();
|
Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId);
|
||||||
|
cancelAuthentication(mAuthRequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,10 +860,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
* @param userId The user to authenticate
|
* @param userId The user to authenticate
|
||||||
* @param operationId The keystore operation associated with authentication
|
* @param operationId The keystore operation associated with authentication
|
||||||
*
|
*
|
||||||
|
* @return A requestId that can be used to cancel this operation.
|
||||||
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||||
public void authenticateUserForOperation(
|
public long authenticateUserForOperation(
|
||||||
@NonNull CancellationSignal cancel,
|
@NonNull CancellationSignal cancel,
|
||||||
@NonNull @CallbackExecutor Executor executor,
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
@NonNull AuthenticationCallback callback,
|
@NonNull AuthenticationCallback callback,
|
||||||
@ -871,7 +880,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
throw new IllegalArgumentException("Must supply a callback");
|
throw new IllegalArgumentException("Must supply a callback");
|
||||||
}
|
}
|
||||||
authenticateInternal(operationId, cancel, executor, callback, userId);
|
|
||||||
|
return authenticateInternal(operationId, cancel, executor, callback, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1002,10 +1012,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
|
authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAuthentication() {
|
private void cancelAuthentication(long requestId) {
|
||||||
if (mService != null) {
|
if (mService != null) {
|
||||||
try {
|
try {
|
||||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
|
mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Unable to cancel authentication", e);
|
Log.e(TAG, "Unable to cancel authentication", e);
|
||||||
}
|
}
|
||||||
@ -1024,7 +1034,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
authenticateInternal(operationId, cancel, executor, callback, userId);
|
authenticateInternal(operationId, cancel, executor, callback, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void authenticateInternal(
|
private long authenticateInternal(
|
||||||
long operationId,
|
long operationId,
|
||||||
@NonNull CancellationSignal cancel,
|
@NonNull CancellationSignal cancel,
|
||||||
@NonNull @CallbackExecutor Executor executor,
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
@ -1040,9 +1050,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
try {
|
try {
|
||||||
if (cancel.isCanceled()) {
|
if (cancel.isCanceled()) {
|
||||||
Log.w(TAG, "Authentication already canceled");
|
Log.w(TAG, "Authentication already canceled");
|
||||||
return;
|
return -1;
|
||||||
} else {
|
|
||||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mExecutor = executor;
|
mExecutor = executor;
|
||||||
@ -1065,14 +1073,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
|||||||
promptInfo = mPromptInfo;
|
promptInfo = mPromptInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver,
|
final long authId = mService.authenticate(mToken, operationId, userId,
|
||||||
mContext.getOpPackageName(), promptInfo);
|
mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo);
|
||||||
|
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
||||||
|
return authId;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote exception while authenticating", e);
|
Log.e(TAG, "Remote exception while authenticating", e);
|
||||||
mExecutor.execute(() -> callback.onAuthenticationError(
|
mExecutor.execute(() -> callback.onAuthenticationError(
|
||||||
BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
|
||||||
mContext.getString(R.string.biometric_error_hw_unavailable)));
|
mContext.getString(R.string.biometric_error_hw_unavailable)));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,13 +41,14 @@ interface IAuthService {
|
|||||||
// Retrieve the package where BIometricOrompt's UI is implemented
|
// Retrieve the package where BIometricOrompt's UI is implemented
|
||||||
String getUiPackage();
|
String getUiPackage();
|
||||||
|
|
||||||
// Requests authentication. The service choose the appropriate biometric to use, and show
|
// Requests authentication. The service chooses the appropriate biometric to use, and shows
|
||||||
// the corresponding BiometricDialog.
|
// the corresponding BiometricDialog. A requestId is returned that can be used to cancel
|
||||||
void authenticate(IBinder token, long sessionId, int userId,
|
// this operation.
|
||||||
|
long authenticate(IBinder token, long sessionId, int userId,
|
||||||
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
|
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
|
||||||
|
|
||||||
// Cancel authentication for the given sessionId
|
// Cancel authentication for the given requestId.
|
||||||
void cancelAuthentication(IBinder token, String opPackageName);
|
void cancelAuthentication(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
|
// TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
|
||||||
// Checks if biometrics can be used.
|
// Checks if biometrics can be used.
|
||||||
|
@ -48,13 +48,13 @@ interface IBiometricAuthenticator {
|
|||||||
// startPreparedClient().
|
// startPreparedClient().
|
||||||
void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
|
void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
|
||||||
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
|
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
|
||||||
int cookie, boolean allowBackgroundAuthentication);
|
long requestId, int cookie, boolean allowBackgroundAuthentication);
|
||||||
|
|
||||||
// Starts authentication with the previously prepared client.
|
// Starts authentication with the previously prepared client.
|
||||||
void startPreparedClient(int cookie);
|
void startPreparedClient(int cookie);
|
||||||
|
|
||||||
// Cancels authentication.
|
// Cancels authentication for the given requestId.
|
||||||
void cancelAuthenticationFromService(IBinder token, String opPackageName);
|
void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Determine if HAL is loaded and ready
|
// Determine if HAL is loaded and ready
|
||||||
boolean isHardwareDetected(String opPackageName);
|
boolean isHardwareDetected(String opPackageName);
|
||||||
|
@ -36,13 +36,14 @@ interface IBiometricService {
|
|||||||
// Retrieve static sensor properties for all biometric sensors
|
// Retrieve static sensor properties for all biometric sensors
|
||||||
List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
|
List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
|
||||||
|
|
||||||
// Requests authentication. The service choose the appropriate biometric to use, and show
|
// Requests authentication. The service chooses the appropriate biometric to use, and shows
|
||||||
// the corresponding BiometricDialog.
|
// the corresponding BiometricDialog. A requestId is returned that can be used to cancel
|
||||||
void authenticate(IBinder token, long operationId, int userId,
|
// this operation.
|
||||||
|
long authenticate(IBinder token, long operationId, int userId,
|
||||||
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
|
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
|
||||||
|
|
||||||
// Cancel authentication for the given session.
|
// Cancel authentication for the given requestId.
|
||||||
void cancelAuthentication(IBinder token, String opPackageName);
|
void cancelAuthentication(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Checks if biometrics can be used.
|
// Checks if biometrics can be used.
|
||||||
int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);
|
int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);
|
||||||
|
@ -263,12 +263,12 @@ public final class CameraExtensionCharacteristics {
|
|||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName component, IBinder binder) {
|
public void onServiceConnected(ComponentName component, IBinder binder) {
|
||||||
mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder);
|
mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder);
|
||||||
mInitFuture.setStatus(true);
|
|
||||||
try {
|
try {
|
||||||
mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported();
|
mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote IPC failed!");
|
Log.e(TAG, "Remote IPC failed!");
|
||||||
}
|
}
|
||||||
|
mInitFuture.setStatus(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ctx.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT |
|
ctx.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT |
|
||||||
|
@ -59,7 +59,7 @@ public class CaptureFailure {
|
|||||||
|
|
||||||
private final CaptureRequest mRequest;
|
private final CaptureRequest mRequest;
|
||||||
private final int mReason;
|
private final int mReason;
|
||||||
private final boolean mDropped;
|
private final boolean mWasImageCaptured;
|
||||||
private final int mSequenceId;
|
private final int mSequenceId;
|
||||||
private final long mFrameNumber;
|
private final long mFrameNumber;
|
||||||
private final String mErrorPhysicalCameraId;
|
private final String mErrorPhysicalCameraId;
|
||||||
@ -68,10 +68,11 @@ public class CaptureFailure {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public CaptureFailure(CaptureRequest request, int reason,
|
public CaptureFailure(CaptureRequest request, int reason,
|
||||||
boolean dropped, int sequenceId, long frameNumber, String errorPhysicalCameraId) {
|
boolean wasImageCaptured, int sequenceId, long frameNumber,
|
||||||
|
String errorPhysicalCameraId) {
|
||||||
mRequest = request;
|
mRequest = request;
|
||||||
mReason = reason;
|
mReason = reason;
|
||||||
mDropped = dropped;
|
mWasImageCaptured = wasImageCaptured;
|
||||||
mSequenceId = sequenceId;
|
mSequenceId = sequenceId;
|
||||||
mFrameNumber = frameNumber;
|
mFrameNumber = frameNumber;
|
||||||
mErrorPhysicalCameraId = errorPhysicalCameraId;
|
mErrorPhysicalCameraId = errorPhysicalCameraId;
|
||||||
@ -141,7 +142,7 @@ public class CaptureFailure {
|
|||||||
* @return boolean True if the image was captured, false otherwise.
|
* @return boolean True if the image was captured, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean wasImageCaptured() {
|
public boolean wasImageCaptured() {
|
||||||
return !mDropped;
|
return mWasImageCaptured;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -873,21 +873,19 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
|||||||
@Override
|
@Override
|
||||||
public int submitBurst(List<Request> requests, IRequestCallback callback) {
|
public int submitBurst(List<Request> requests, IRequestCallback callback) {
|
||||||
int seqId = -1;
|
int seqId = -1;
|
||||||
synchronized (mInterfaceLock) {
|
try {
|
||||||
try {
|
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
||||||
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
|
||||||
ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
|
for (Request request : requests) {
|
||||||
for (Request request : requests) {
|
captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
|
||||||
captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
|
mCameraConfigMap));
|
||||||
mCameraConfigMap));
|
|
||||||
}
|
|
||||||
seqId = mCaptureSession.captureBurstRequests(captureRequests,
|
|
||||||
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
|
||||||
} catch (CameraAccessException e) {
|
|
||||||
Log.e(TAG, "Failed to submit capture requests!");
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
Log.e(TAG, "Capture session closed!");
|
|
||||||
}
|
}
|
||||||
|
seqId = mCaptureSession.captureBurstRequests(captureRequests,
|
||||||
|
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
||||||
|
} catch (CameraAccessException e) {
|
||||||
|
Log.e(TAG, "Failed to submit capture requests!");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Log.e(TAG, "Capture session closed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return seqId;
|
return seqId;
|
||||||
@ -896,18 +894,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
|||||||
@Override
|
@Override
|
||||||
public int setRepeating(Request request, IRequestCallback callback) {
|
public int setRepeating(Request request, IRequestCallback callback) {
|
||||||
int seqId = -1;
|
int seqId = -1;
|
||||||
synchronized (mInterfaceLock) {
|
try {
|
||||||
try {
|
CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
|
||||||
CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
|
request, mCameraConfigMap);
|
||||||
request, mCameraConfigMap);
|
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
||||||
CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
|
seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
|
||||||
seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
|
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
||||||
new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
|
} catch (CameraAccessException e) {
|
||||||
} catch (CameraAccessException e) {
|
Log.e(TAG, "Failed to enable repeating request!");
|
||||||
Log.e(TAG, "Failed to enable repeating request!");
|
} catch (IllegalStateException e) {
|
||||||
} catch (IllegalStateException e) {
|
Log.e(TAG, "Capture session closed!");
|
||||||
Log.e(TAG, "Capture session closed!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return seqId;
|
return seqId;
|
||||||
@ -915,27 +911,23 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void abortCaptures() {
|
public void abortCaptures() {
|
||||||
synchronized (mInterfaceLock) {
|
try {
|
||||||
try {
|
mCaptureSession.abortCaptures();
|
||||||
mCaptureSession.abortCaptures();
|
} catch (CameraAccessException e) {
|
||||||
} catch (CameraAccessException e) {
|
Log.e(TAG, "Failed during capture abort!");
|
||||||
Log.e(TAG, "Failed during capture abort!");
|
} catch (IllegalStateException e) {
|
||||||
} catch (IllegalStateException e) {
|
Log.e(TAG, "Capture session closed!");
|
||||||
Log.e(TAG, "Capture session closed!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopRepeating() {
|
public void stopRepeating() {
|
||||||
synchronized (mInterfaceLock) {
|
try {
|
||||||
try {
|
mCaptureSession.stopRepeating();
|
||||||
mCaptureSession.stopRepeating();
|
} catch (CameraAccessException e) {
|
||||||
} catch (CameraAccessException e) {
|
Log.e(TAG, "Failed during repeating capture stop!");
|
||||||
Log.e(TAG, "Failed during repeating capture stop!");
|
} catch (IllegalStateException e) {
|
||||||
} catch (IllegalStateException e) {
|
Log.e(TAG, "Capture session closed!");
|
||||||
Log.e(TAG, "Capture session closed!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,9 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
|
private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
|
||||||
new SparseArray<CaptureCallbackHolder>();
|
new SparseArray<CaptureCallbackHolder>();
|
||||||
|
|
||||||
|
/** map request IDs which have batchedOutputs to requestCount*/
|
||||||
|
private HashMap<Integer, Integer> mBatchOutputMap = new HashMap<>();
|
||||||
|
|
||||||
private int mRepeatingRequestId = REQUEST_ID_NONE;
|
private int mRepeatingRequestId = REQUEST_ID_NONE;
|
||||||
// Latest repeating request list's types
|
// Latest repeating request list's types
|
||||||
private int[] mRepeatingRequestTypes;
|
private int[] mRepeatingRequestTypes;
|
||||||
@ -973,6 +976,7 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null);
|
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null);
|
||||||
mIdle = true;
|
mIdle = true;
|
||||||
mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>();
|
mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>();
|
||||||
|
mBatchOutputMap = new HashMap<>();
|
||||||
mFrameNumberTracker = new FrameNumberTracker();
|
mFrameNumberTracker = new FrameNumberTracker();
|
||||||
|
|
||||||
mCurrentSession.closeWithoutDraining();
|
mCurrentSession.closeWithoutDraining();
|
||||||
@ -1179,6 +1183,41 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
return requestTypes;
|
return requestTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasBatchedOutputs(List<CaptureRequest> requestList) {
|
||||||
|
boolean hasBatchedOutputs = true;
|
||||||
|
for (int i = 0; i < requestList.size(); i++) {
|
||||||
|
CaptureRequest request = requestList.get(i);
|
||||||
|
if (!request.isPartOfCRequestList()) {
|
||||||
|
hasBatchedOutputs = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
Collection<Surface> targets = request.getTargets();
|
||||||
|
if (targets.size() != 2) {
|
||||||
|
hasBatchedOutputs = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasBatchedOutputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTracker(int requestId, long frameNumber,
|
||||||
|
int requestType, CaptureResult result, boolean isPartialResult) {
|
||||||
|
int requestCount = 1;
|
||||||
|
// If the request has batchedOutputs update each frame within the batch.
|
||||||
|
if (mBatchOutputMap.containsKey(requestId)) {
|
||||||
|
requestCount = mBatchOutputMap.get(requestId);
|
||||||
|
for (int i = 0; i < requestCount; i++) {
|
||||||
|
mFrameNumberTracker.updateTracker(frameNumber - (requestCount - 1 - i),
|
||||||
|
result, isPartialResult, requestType);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mFrameNumberTracker.updateTracker(frameNumber, result,
|
||||||
|
isPartialResult, requestType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
|
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
|
||||||
Executor executor, boolean repeating) throws CameraAccessException {
|
Executor executor, boolean repeating) throws CameraAccessException {
|
||||||
|
|
||||||
@ -1224,6 +1263,14 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
request.recoverStreamIdToSurface();
|
request.recoverStreamIdToSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the request has batched outputs, then store the
|
||||||
|
// requestCount and requestId in the map.
|
||||||
|
boolean hasBatchedOutputs = hasBatchedOutputs(requestList);
|
||||||
|
if (hasBatchedOutputs) {
|
||||||
|
int requestCount = requestList.size();
|
||||||
|
mBatchOutputMap.put(requestInfo.getRequestId(), requestCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
mCaptureCallbackMap.put(requestInfo.getRequestId(),
|
mCaptureCallbackMap.put(requestInfo.getRequestId(),
|
||||||
new CaptureCallbackHolder(
|
new CaptureCallbackHolder(
|
||||||
@ -1820,7 +1867,7 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
final CaptureFailure failure = new CaptureFailure(
|
final CaptureFailure failure = new CaptureFailure(
|
||||||
request,
|
request,
|
||||||
reason,
|
reason,
|
||||||
/*dropped*/ mayHaveBuffers,
|
mayHaveBuffers,
|
||||||
requestId,
|
requestId,
|
||||||
frameNumber,
|
frameNumber,
|
||||||
errorPhysicalCameraId);
|
errorPhysicalCameraId);
|
||||||
@ -1839,8 +1886,18 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.v(TAG, String.format("got error frame %d", frameNumber));
|
Log.v(TAG, String.format("got error frame %d", frameNumber));
|
||||||
}
|
}
|
||||||
mFrameNumberTracker.updateTracker(frameNumber,
|
|
||||||
/*error*/true, request.getRequestType());
|
// Update FrameNumberTracker for every frame during HFR mode.
|
||||||
|
if (mBatchOutputMap.containsKey(requestId)) {
|
||||||
|
for (int i = 0; i < mBatchOutputMap.get(requestId); i++) {
|
||||||
|
mFrameNumberTracker.updateTracker(frameNumber - (subsequenceId - i),
|
||||||
|
/*error*/true, request.getRequestType());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mFrameNumberTracker.updateTracker(frameNumber,
|
||||||
|
/*error*/true, request.getRequestType());
|
||||||
|
}
|
||||||
|
|
||||||
checkAndFireSequenceComplete();
|
checkAndFireSequenceComplete();
|
||||||
|
|
||||||
// Dispatch the failure callback
|
// Dispatch the failure callback
|
||||||
@ -2023,7 +2080,6 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
public void onResultReceived(CameraMetadataNative result,
|
public void onResultReceived(CameraMetadataNative result,
|
||||||
CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
|
CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
|
||||||
int requestId = resultExtras.getRequestId();
|
int requestId = resultExtras.getRequestId();
|
||||||
long frameNumber = resultExtras.getFrameNumber();
|
long frameNumber = resultExtras.getFrameNumber();
|
||||||
|
|
||||||
@ -2064,8 +2120,8 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
+ frameNumber);
|
+ frameNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
|
updateTracker(requestId, frameNumber, requestType, /*result*/null,
|
||||||
requestType);
|
isPartialResult);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2077,8 +2133,9 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
+ frameNumber);
|
+ frameNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
|
updateTracker(requestId, frameNumber, requestType, /*result*/null,
|
||||||
requestType);
|
isPartialResult);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2184,9 +2241,7 @@ public class CameraDeviceImpl extends CameraDevice
|
|||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect the partials for a total result; or mark the frame as totally completed
|
updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult);
|
||||||
mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
|
|
||||||
requestType);
|
|
||||||
|
|
||||||
// Fire onCaptureSequenceCompleted
|
// Fire onCaptureSequenceCompleted
|
||||||
if (!isPartialResult) {
|
if (!isPartialResult) {
|
||||||
|
@ -58,7 +58,7 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
|
|||||||
|
|
||||||
private static final class JpegParameters {
|
private static final class JpegParameters {
|
||||||
public HashSet<Long> mTimeStamps = new HashSet<>();
|
public HashSet<Long> mTimeStamps = new HashSet<>();
|
||||||
public int mRotation = JPEG_DEFAULT_ROTATION; // CCW multiple of 90 degrees
|
public int mRotation = JPEG_DEFAULT_ROTATION; // CW multiple of 90 degrees
|
||||||
public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100]
|
public int mQuality = JPEG_DEFAULT_QUALITY; // [0..100]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,8 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
|
|||||||
Integer orientation = captureBundles.get(0).captureResult.get(
|
Integer orientation = captureBundles.get(0).captureResult.get(
|
||||||
CaptureResult.JPEG_ORIENTATION);
|
CaptureResult.JPEG_ORIENTATION);
|
||||||
if (orientation != null) {
|
if (orientation != null) {
|
||||||
ret.mRotation = orientation / 90;
|
// The jpeg encoder expects CCW rotation, convert from CW
|
||||||
|
ret.mRotation = (360 - (orientation % 360)) / 90;
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION);
|
Log.w(TAG, "No jpeg rotation set, using default: " + JPEG_DEFAULT_ROTATION);
|
||||||
}
|
}
|
||||||
|
@ -60,12 +60,18 @@ public final class BrightnessInfo implements Parcelable {
|
|||||||
/** Brightness */
|
/** Brightness */
|
||||||
public final float brightness;
|
public final float brightness;
|
||||||
|
|
||||||
|
/** Brightness after {@link DisplayPowerController} adjustments */
|
||||||
|
public final float adjustedBrightness;
|
||||||
|
|
||||||
/** Current minimum supported brightness. */
|
/** Current minimum supported brightness. */
|
||||||
public final float brightnessMinimum;
|
public final float brightnessMinimum;
|
||||||
|
|
||||||
/** Current maximum supported brightness. */
|
/** Current maximum supported brightness. */
|
||||||
public final float brightnessMaximum;
|
public final float brightnessMaximum;
|
||||||
|
|
||||||
|
/** Brightness values greater than this point are only used in High Brightness Mode. */
|
||||||
|
public final float highBrightnessTransitionPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current state of high brightness mode.
|
* Current state of high brightness mode.
|
||||||
* Can be any of HIGH_BRIGHTNESS_MODE_* values.
|
* Can be any of HIGH_BRIGHTNESS_MODE_* values.
|
||||||
@ -73,11 +79,20 @@ public final class BrightnessInfo implements Parcelable {
|
|||||||
public final int highBrightnessMode;
|
public final int highBrightnessMode;
|
||||||
|
|
||||||
public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum,
|
public BrightnessInfo(float brightness, float brightnessMinimum, float brightnessMaximum,
|
||||||
@HighBrightnessMode int highBrightnessMode) {
|
@HighBrightnessMode int highBrightnessMode, float highBrightnessTransitionPoint) {
|
||||||
|
this(brightness, brightness, brightnessMinimum, brightnessMaximum, highBrightnessMode,
|
||||||
|
highBrightnessTransitionPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BrightnessInfo(float brightness, float adjustedBrightness, float brightnessMinimum,
|
||||||
|
float brightnessMaximum, @HighBrightnessMode int highBrightnessMode,
|
||||||
|
float highBrightnessTransitionPoint) {
|
||||||
this.brightness = brightness;
|
this.brightness = brightness;
|
||||||
|
this.adjustedBrightness = adjustedBrightness;
|
||||||
this.brightnessMinimum = brightnessMinimum;
|
this.brightnessMinimum = brightnessMinimum;
|
||||||
this.brightnessMaximum = brightnessMaximum;
|
this.brightnessMaximum = brightnessMaximum;
|
||||||
this.highBrightnessMode = highBrightnessMode;
|
this.highBrightnessMode = highBrightnessMode;
|
||||||
|
this.highBrightnessTransitionPoint = highBrightnessTransitionPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,9 +118,11 @@ public final class BrightnessInfo implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeFloat(brightness);
|
dest.writeFloat(brightness);
|
||||||
|
dest.writeFloat(adjustedBrightness);
|
||||||
dest.writeFloat(brightnessMinimum);
|
dest.writeFloat(brightnessMinimum);
|
||||||
dest.writeFloat(brightnessMaximum);
|
dest.writeFloat(brightnessMaximum);
|
||||||
dest.writeInt(highBrightnessMode);
|
dest.writeInt(highBrightnessMode);
|
||||||
|
dest.writeFloat(highBrightnessTransitionPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR =
|
public static final @android.annotation.NonNull Creator<BrightnessInfo> CREATOR =
|
||||||
@ -123,9 +140,11 @@ public final class BrightnessInfo implements Parcelable {
|
|||||||
|
|
||||||
private BrightnessInfo(Parcel source) {
|
private BrightnessInfo(Parcel source) {
|
||||||
brightness = source.readFloat();
|
brightness = source.readFloat();
|
||||||
|
adjustedBrightness = source.readFloat();
|
||||||
brightnessMinimum = source.readFloat();
|
brightnessMinimum = source.readFloat();
|
||||||
brightnessMaximum = source.readFloat();
|
brightnessMaximum = source.readFloat();
|
||||||
highBrightnessMode = source.readInt();
|
highBrightnessMode = source.readInt();
|
||||||
|
highBrightnessTransitionPoint = source.readFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1257,6 +1257,23 @@ public final class DisplayManager {
|
|||||||
*/
|
*/
|
||||||
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
|
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
|
||||||
"fixed_refresh_rate_high_ambient_brightness_thresholds";
|
"fixed_refresh_rate_high_ambient_brightness_thresholds";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for refresh rate when the device is in high brightness mode for sunlight visility.
|
||||||
|
*
|
||||||
|
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||||
|
* @see android.R.integer#config_defaultRefreshRateInHbmSunlight
|
||||||
|
*/
|
||||||
|
String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for refresh rate when the device is in high brightness mode for HDR.
|
||||||
|
*
|
||||||
|
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||||
|
* @see android.R.integer#config_defaultRefreshRateInHbmHdr
|
||||||
|
*/
|
||||||
|
String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key for default peak refresh rate
|
* Key for default peak refresh rate
|
||||||
*
|
*
|
||||||
|
@ -361,6 +361,11 @@ public final class DisplayManagerGlobal {
|
|||||||
for (int i = 0; i < numListeners; i++) {
|
for (int i = 0; i < numListeners; i++) {
|
||||||
mask |= mDisplayListeners.get(i).mEventsMask;
|
mask |= mDisplayListeners.get(i).mEventsMask;
|
||||||
}
|
}
|
||||||
|
if (mDispatchNativeCallbacks) {
|
||||||
|
mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED
|
||||||
|
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
|
||||||
|
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
|
||||||
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,12 +1052,17 @@ public final class DisplayManagerGlobal {
|
|||||||
|
|
||||||
private static native void nSignalNativeCallbacks(float refreshRate);
|
private static native void nSignalNativeCallbacks(float refreshRate);
|
||||||
|
|
||||||
// Called from AChoreographer via JNI.
|
/**
|
||||||
// Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
|
* Called from AChoreographer via JNI.
|
||||||
private void registerNativeChoreographerForRefreshRateCallbacks() {
|
* Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
|
||||||
|
* Public for unit testing to be able to call this method.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public void registerNativeChoreographerForRefreshRateCallbacks() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
registerCallbackIfNeededLocked();
|
|
||||||
mDispatchNativeCallbacks = true;
|
mDispatchNativeCallbacks = true;
|
||||||
|
registerCallbackIfNeededLocked();
|
||||||
|
updateCallbackIfNeededLocked();
|
||||||
DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
|
DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
|
||||||
if (display != null) {
|
if (display != null) {
|
||||||
// We need to tell AChoreographer instances the current refresh rate so that apps
|
// We need to tell AChoreographer instances the current refresh rate so that apps
|
||||||
@ -1063,11 +1073,16 @@ public final class DisplayManagerGlobal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from AChoreographer via JNI.
|
/**
|
||||||
// Unregisters AChoreographer from receiving refresh rate callbacks.
|
* Called from AChoreographer via JNI.
|
||||||
private void unregisterNativeChoreographerForRefreshRateCallbacks() {
|
* Unregisters AChoreographer from receiving refresh rate callbacks.
|
||||||
|
* Public for unit testing to be able to call this method.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public void unregisterNativeChoreographerForRefreshRateCallbacks() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mDispatchNativeCallbacks = false;
|
mDispatchNativeCallbacks = false;
|
||||||
|
updateCallbackIfNeededLocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ import java.util.List;
|
|||||||
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
|
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
|
||||||
|
|
||||||
private static final String TAG = "FaceManager";
|
private static final String TAG = "FaceManager";
|
||||||
private static final boolean DEBUG = true;
|
|
||||||
private static final int MSG_ENROLL_RESULT = 100;
|
private static final int MSG_ENROLL_RESULT = 100;
|
||||||
private static final int MSG_ACQUIRED = 101;
|
private static final int MSG_ACQUIRED = 101;
|
||||||
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
|
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
|
||||||
@ -207,13 +207,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
|||||||
throw new IllegalArgumentException("Must supply an authentication callback");
|
throw new IllegalArgumentException("Must supply an authentication callback");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancel != null) {
|
if (cancel != null && cancel.isCanceled()) {
|
||||||
if (cancel.isCanceled()) {
|
Slog.w(TAG, "authentication already canceled");
|
||||||
Slog.w(TAG, "authentication already canceled");
|
return;
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mService != null) {
|
if (mService != null) {
|
||||||
@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
|||||||
mCryptoObject = crypto;
|
mCryptoObject = crypto;
|
||||||
final long operationId = crypto != null ? crypto.getOpId() : 0;
|
final long operationId = crypto != null ? crypto.getOpId() : 0;
|
||||||
Trace.beginSection("FaceManager#authenticate");
|
Trace.beginSection("FaceManager#authenticate");
|
||||||
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
|
final long authId = mService.authenticate(mToken, operationId, userId,
|
||||||
mContext.getOpPackageName(), isKeyguardBypassEnabled);
|
mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
|
||||||
|
if (cancel != null) {
|
||||||
|
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
||||||
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
||||||
if (callback != null) {
|
// Though this may not be a hardware issue, it will cause apps to give up or
|
||||||
// Though this may not be a hardware issue, it will cause apps to give up or
|
// try again later.
|
||||||
// try again later.
|
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
|
||||||
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
|
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
|
||||||
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
|
0 /* vendorCode */));
|
||||||
0 /* vendorCode */));
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
Trace.endSection();
|
Trace.endSection();
|
||||||
}
|
}
|
||||||
@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
|||||||
if (cancel.isCanceled()) {
|
if (cancel.isCanceled()) {
|
||||||
Slog.w(TAG, "Detection already cancelled");
|
Slog.w(TAG, "Detection already cancelled");
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mFaceDetectionCallback = callback;
|
mFaceDetectionCallback = callback;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
|
final long authId = mService.detectFace(
|
||||||
|
mToken, userId, mServiceReceiver, mContext.getOpPackageName());
|
||||||
|
cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId));
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.w(TAG, "Remote exception when requesting finger detect", e);
|
Slog.w(TAG, "Remote exception when requesting finger detect", e);
|
||||||
}
|
}
|
||||||
@ -726,23 +723,23 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAuthentication(CryptoObject cryptoObject) {
|
private void cancelAuthentication(long requestId) {
|
||||||
if (mService != null) {
|
if (mService != null) {
|
||||||
try {
|
try {
|
||||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
|
mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelFaceDetect() {
|
private void cancelFaceDetect(long requestId) {
|
||||||
if (mService == null) {
|
if (mService == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mService.cancelFaceDetect(mToken, mContext.getOpPackageName());
|
mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
@ -794,9 +791,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
|||||||
// This is used as a last resort in case a vendor string is missing
|
// This is used as a last resort in case a vendor string is missing
|
||||||
// It should not happen for anything other than FACE_ERROR_VENDOR, but
|
// It should not happen for anything other than FACE_ERROR_VENDOR, but
|
||||||
// warn and use the default if all else fails.
|
// warn and use the default if all else fails.
|
||||||
// TODO(b/196639965): update string
|
|
||||||
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
|
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
|
||||||
return "";
|
return context.getString(
|
||||||
|
com.android.internal.R.string.face_error_vendor_unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1110,22 +1107,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class OnAuthenticationCancelListener implements OnCancelListener {
|
private class OnAuthenticationCancelListener implements OnCancelListener {
|
||||||
private final CryptoObject mCrypto;
|
private final long mAuthRequestId;
|
||||||
|
|
||||||
OnAuthenticationCancelListener(CryptoObject crypto) {
|
OnAuthenticationCancelListener(long id) {
|
||||||
mCrypto = crypto;
|
mAuthRequestId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel() {
|
public void onCancel() {
|
||||||
cancelAuthentication(mCrypto);
|
Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId);
|
||||||
|
cancelAuthentication(mAuthRequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OnFaceDetectionCancelListener implements OnCancelListener {
|
private class OnFaceDetectionCancelListener implements OnCancelListener {
|
||||||
|
private final long mAuthRequestId;
|
||||||
|
|
||||||
|
OnFaceDetectionCancelListener(long id) {
|
||||||
|
mAuthRequestId = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel() {
|
public void onCancel() {
|
||||||
cancelFaceDetect();
|
Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId);
|
||||||
|
cancelFaceDetect(mAuthRequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,34 +44,36 @@ interface IFaceService {
|
|||||||
// Retrieve static sensor properties for the specified sensor
|
// Retrieve static sensor properties for the specified sensor
|
||||||
FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
|
FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
|
||||||
|
|
||||||
// Authenticate the given sessionId with a face
|
// Authenticate with a face. A requestId is returned that can be used to cancel this operation.
|
||||||
void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
|
long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
|
||||||
String opPackageName, boolean isKeyguardBypassEnabled);
|
String opPackageName, boolean isKeyguardBypassEnabled);
|
||||||
|
|
||||||
// Uses the face hardware to detect for the presence of a face, without giving details
|
// Uses the face hardware to detect for the presence of a face, without giving details
|
||||||
// about accept/reject/lockout.
|
// about accept/reject/lockout. A requestId is returned that can be used to cancel this
|
||||||
void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
|
// operation.
|
||||||
|
long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
|
||||||
|
|
||||||
// This method prepares the service to start authenticating, but doesn't start authentication.
|
// This method prepares the service to start authenticating, but doesn't start authentication.
|
||||||
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
|
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
|
||||||
// called from BiometricService. The additional uid, pid, userId arguments should be determined
|
// called from BiometricService. The additional uid, pid, userId arguments should be determined
|
||||||
// by BiometricService. To start authentication after the clients are ready, use
|
// by BiometricService. To start authentication after the clients are ready, use
|
||||||
// startPreparedClient().
|
// startPreparedClient().
|
||||||
void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
|
void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token,
|
||||||
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
|
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
|
||||||
int cookie, boolean allowBackgroundAuthentication);
|
String opPackageName, long requestId, int cookie,
|
||||||
|
boolean allowBackgroundAuthentication);
|
||||||
|
|
||||||
// Starts authentication with the previously prepared client.
|
// Starts authentication with the previously prepared client.
|
||||||
void startPreparedClient(int sensorId, int cookie);
|
void startPreparedClient(int sensorId, int cookie);
|
||||||
|
|
||||||
// Cancel authentication for the given sessionId
|
// Cancel authentication for the given requestId.
|
||||||
void cancelAuthentication(IBinder token, String opPackageName);
|
void cancelAuthentication(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Cancel face detection
|
// Cancel face detection for the given requestId.
|
||||||
void cancelFaceDetect(IBinder token, String opPackageName);
|
void cancelFaceDetect(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Same as above, with extra arguments.
|
// Same as above, with extra arguments.
|
||||||
void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
|
void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Start face enrollment
|
// Start face enrollment
|
||||||
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
|
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
|
||||||
|
@ -146,6 +146,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
private CryptoObject mCryptoObject;
|
private CryptoObject mCryptoObject;
|
||||||
@Nullable private RemoveTracker mRemoveTracker;
|
@Nullable private RemoveTracker mRemoveTracker;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
|
@Nullable private float[] mEnrollStageThresholds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of properties for all fingerprint sensors on the device.
|
* Retrieves a list of properties for all fingerprint sensors on the device.
|
||||||
@ -189,22 +190,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class OnAuthenticationCancelListener implements OnCancelListener {
|
private class OnAuthenticationCancelListener implements OnCancelListener {
|
||||||
private android.hardware.biometrics.CryptoObject mCrypto;
|
private final long mAuthRequestId;
|
||||||
|
|
||||||
public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
|
OnAuthenticationCancelListener(long id) {
|
||||||
mCrypto = crypto;
|
mAuthRequestId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel() {
|
public void onCancel() {
|
||||||
cancelAuthentication(mCrypto);
|
Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
|
||||||
|
cancelAuthentication(mAuthRequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OnFingerprintDetectionCancelListener implements OnCancelListener {
|
private class OnFingerprintDetectionCancelListener implements OnCancelListener {
|
||||||
|
private final long mAuthRequestId;
|
||||||
|
|
||||||
|
OnFingerprintDetectionCancelListener(long id) {
|
||||||
|
mAuthRequestId = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel() {
|
public void onCancel() {
|
||||||
cancelFingerprintDetect();
|
Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId);
|
||||||
|
cancelFingerprintDetect(mAuthRequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,13 +561,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
throw new IllegalArgumentException("Must supply an authentication callback");
|
throw new IllegalArgumentException("Must supply an authentication callback");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancel != null) {
|
if (cancel != null && cancel.isCanceled()) {
|
||||||
if (cancel.isCanceled()) {
|
Slog.w(TAG, "authentication already canceled");
|
||||||
Slog.w(TAG, "authentication already canceled");
|
return;
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mService != null) {
|
if (mService != null) {
|
||||||
@ -567,8 +572,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
mAuthenticationCallback = callback;
|
mAuthenticationCallback = callback;
|
||||||
mCryptoObject = crypto;
|
mCryptoObject = crypto;
|
||||||
final long operationId = crypto != null ? crypto.getOpId() : 0;
|
final long operationId = crypto != null ? crypto.getOpId() : 0;
|
||||||
mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver,
|
final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
|
||||||
mContext.getOpPackageName());
|
mServiceReceiver, mContext.getOpPackageName());
|
||||||
|
if (cancel != null) {
|
||||||
|
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
|
||||||
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
Slog.w(TAG, "Remote exception while authenticating: ", e);
|
||||||
// Though this may not be a hardware issue, it will cause apps to give up or try
|
// Though this may not be a hardware issue, it will cause apps to give up or try
|
||||||
@ -595,15 +603,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
if (cancel.isCanceled()) {
|
if (cancel.isCanceled()) {
|
||||||
Slog.w(TAG, "Detection already cancelled");
|
Slog.w(TAG, "Detection already cancelled");
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mFingerprintDetectionCallback = callback;
|
mFingerprintDetectionCallback = callback;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mService.detectFingerprint(mToken, userId, mServiceReceiver,
|
final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
|
||||||
mContext.getOpPackageName());
|
mContext.getOpPackageName());
|
||||||
|
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.w(TAG, "Remote exception when requesting finger detect", e);
|
Slog.w(TAG, "Remote exception when requesting finger detect", e);
|
||||||
}
|
}
|
||||||
@ -843,26 +850,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
return hasEnrolledFingerprints(userId);
|
return hasEnrolledFingerprints(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the specified user has enrollments in any of the specified sensors.
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
|
||||||
public boolean hasEnrolledTemplatesForAnySensor(int userId,
|
|
||||||
@NonNull List<FingerprintSensorPropertiesInternal> sensors) {
|
|
||||||
if (mService == null) {
|
|
||||||
Slog.w(TAG, "hasEnrolledTemplatesForAnySensor: no fingerprint service");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return mService.hasEnrolledTemplatesForAnySensor(userId, sensors,
|
|
||||||
mContext.getOpPackageName());
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw e.rethrowFromSystemServer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@ -1320,26 +1307,66 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) {
|
private void cancelAuthentication(long requestId) {
|
||||||
if (mService != null) try {
|
if (mService != null) try {
|
||||||
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
|
mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelFingerprintDetect() {
|
private void cancelFingerprintDetect(long requestId) {
|
||||||
if (mService == null) {
|
if (mService == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName());
|
mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public int getEnrollStageCount() {
|
||||||
|
if (mEnrollStageThresholds == null) {
|
||||||
|
mEnrollStageThresholds = createEnrollStageThresholds(mContext);
|
||||||
|
}
|
||||||
|
return mEnrollStageThresholds.length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public float getEnrollStageThreshold(int index) {
|
||||||
|
if (mEnrollStageThresholds == null) {
|
||||||
|
mEnrollStageThresholds = createEnrollStageThresholds(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 0 || index > mEnrollStageThresholds.length) {
|
||||||
|
Slog.w(TAG, "Unsupported enroll stage index: " + index);
|
||||||
|
return index < 0 ? 0f : 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The implicit threshold for the final stage is always 1.
|
||||||
|
return index == mEnrollStageThresholds.length ? 1f : mEnrollStageThresholds[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static float[] createEnrollStageThresholds(@NonNull Context context) {
|
||||||
|
// TODO(b/200604947): Fetch this value from FingerprintService, rather than internal config
|
||||||
|
final String[] enrollStageThresholdStrings = context.getResources().getStringArray(
|
||||||
|
com.android.internal.R.array.config_udfps_enroll_stage_thresholds);
|
||||||
|
|
||||||
|
final float[] enrollStageThresholds = new float[enrollStageThresholdStrings.length];
|
||||||
|
for (int i = 0; i < enrollStageThresholds.length; i++) {
|
||||||
|
enrollStageThresholds[i] = Float.parseFloat(enrollStageThresholdStrings[i]);
|
||||||
|
}
|
||||||
|
return enrollStageThresholds;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@ -1390,9 +1417,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
|||||||
// This is used as a last resort in case a vendor string is missing
|
// This is used as a last resort in case a vendor string is missing
|
||||||
// It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but
|
// It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but
|
||||||
// warn and use the default if all else fails.
|
// warn and use the default if all else fails.
|
||||||
// TODO(b/196639965): update string
|
|
||||||
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
|
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
|
||||||
return "";
|
return context.getString(
|
||||||
|
com.android.internal.R.string.fingerprint_error_vendor_unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener
|
|||||||
* Defines behavior in response to state update
|
* Defines behavior in response to state update
|
||||||
* @param newState new state of fingerprint sensor
|
* @param newState new state of fingerprint sensor
|
||||||
*/
|
*/
|
||||||
public abstract void onStateChanged(@FingerprintStateListener.State int newState);
|
public void onStateChanged(@FingerprintStateListener.State int newState) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when enrollment state changes for the specified user
|
||||||
|
*/
|
||||||
|
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {};
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,16 @@ interface IFingerprintService {
|
|||||||
// Retrieve static sensor properties for the specified sensor
|
// Retrieve static sensor properties for the specified sensor
|
||||||
FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
|
FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
|
||||||
|
|
||||||
// Authenticate the given sessionId with a fingerprint. This is protected by
|
// Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC
|
||||||
// USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
|
// permission. This is effectively deprecated, since it only comes through FingerprintManager
|
||||||
// through FingerprintManager now.
|
// now. A requestId is returned that can be used to cancel this operation.
|
||||||
void authenticate(IBinder token, long operationId, int sensorId, int userId,
|
long authenticate(IBinder token, long operationId, int sensorId, int userId,
|
||||||
IFingerprintServiceReceiver receiver, String opPackageName);
|
IFingerprintServiceReceiver receiver, String opPackageName);
|
||||||
|
|
||||||
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details
|
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details
|
||||||
// about accept/reject/lockout.
|
// about accept/reject/lockout. A requestId is returned that can be used to cancel this
|
||||||
void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
|
// operation.
|
||||||
|
long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
|
||||||
String opPackageName);
|
String opPackageName);
|
||||||
|
|
||||||
// This method prepares the service to start authenticating, but doesn't start authentication.
|
// This method prepares the service to start authenticating, but doesn't start authentication.
|
||||||
@ -65,21 +66,21 @@ interface IFingerprintService {
|
|||||||
// by BiometricService. To start authentication after the clients are ready, use
|
// by BiometricService. To start authentication after the clients are ready, use
|
||||||
// startPreparedClient().
|
// startPreparedClient().
|
||||||
void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
|
void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
|
||||||
IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
|
IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
|
||||||
boolean allowBackgroundAuthentication);
|
int cookie, boolean allowBackgroundAuthentication);
|
||||||
|
|
||||||
// Starts authentication with the previously prepared client.
|
// Starts authentication with the previously prepared client.
|
||||||
void startPreparedClient(int sensorId, int cookie);
|
void startPreparedClient(int sensorId, int cookie);
|
||||||
|
|
||||||
// Cancel authentication for the given sessionId
|
// Cancel authentication for the given requestId.
|
||||||
void cancelAuthentication(IBinder token, String opPackageName);
|
void cancelAuthentication(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Cancel finger detection
|
// Cancel finger detection for the given requestId.
|
||||||
void cancelFingerprintDetect(IBinder token, String opPackageName);
|
void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
|
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
|
||||||
// an additional uid, pid, userid.
|
// an additional uid, pid, userid.
|
||||||
void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
|
void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
|
||||||
|
|
||||||
// Start fingerprint enrollment
|
// Start fingerprint enrollment
|
||||||
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
|
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
|
||||||
@ -119,9 +120,6 @@ interface IFingerprintService {
|
|||||||
// Determine if a user has at least one enrolled fingerprint.
|
// Determine if a user has at least one enrolled fingerprint.
|
||||||
boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
|
boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
|
||||||
|
|
||||||
// Determine if a user has at least one enrolled fingerprint in any of the specified sensors
|
|
||||||
boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName);
|
|
||||||
|
|
||||||
// Return the LockoutTracker status for the specified user
|
// Return the LockoutTracker status for the specified user
|
||||||
int getLockoutModeForUser(int sensorId, int userId);
|
int getLockoutModeForUser(int sensorId, int userId);
|
||||||
|
|
||||||
|
@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint;
|
|||||||
*/
|
*/
|
||||||
oneway interface IFingerprintStateListener {
|
oneway interface IFingerprintStateListener {
|
||||||
void onStateChanged(int newState);
|
void onStateChanged(int newState);
|
||||||
|
void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
|
||||||
}
|
}
|
||||||
|
@ -1749,12 +1749,12 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
|
if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((mInputEditorInfo != null
|
if (mInputEditorInfo != null
|
||||||
&& (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0)
|
&& ((mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0
|
||||||
// If app window has portrait orientation, regardless of what display orientation
|
// If app window has portrait orientation, regardless of what display orientation
|
||||||
// is, IME shouldn't use fullscreen-mode.
|
// is, IME shouldn't use fullscreen-mode.
|
||||||
|| (mInputEditorInfo.internalImeOptions
|
|| (mInputEditorInfo.internalImeOptions
|
||||||
& EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) {
|
& EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -270,6 +270,16 @@ public final class BatteryUsageStats implements Parcelable {
|
|||||||
return mUserBatteryConsumers;
|
return mUserBatteryConsumers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of custom power components in order, so the first name in the array
|
||||||
|
* corresponds to the custom componentId
|
||||||
|
* {@link BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID}.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String[] getCustomPowerComponentNames() {
|
||||||
|
return mCustomPowerComponentNames;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
|
* Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
|
||||||
*/
|
*/
|
||||||
|
@ -74,7 +74,7 @@ public final class BinderProxy implements IBinder {
|
|||||||
private static final int MAIN_INDEX_SIZE = 1 << LOG_MAIN_INDEX_SIZE;
|
private static final int MAIN_INDEX_SIZE = 1 << LOG_MAIN_INDEX_SIZE;
|
||||||
private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1;
|
private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1;
|
||||||
// Debuggable builds will throw an AssertionError if the number of map entries exceeds:
|
// Debuggable builds will throw an AssertionError if the number of map entries exceeds:
|
||||||
private static final int CRASH_AT_SIZE = 20_000;
|
private static final int CRASH_AT_SIZE = 25_000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We next warn when we exceed this bucket size.
|
* We next warn when we exceed this bucket size.
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package android.os;
|
package android.os;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.GameManager;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -26,8 +27,6 @@ import android.content.pm.IPackageManager;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.res.AssetFileDescriptor;
|
|
||||||
import android.content.res.AssetManager;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -37,9 +36,6 @@ import dalvik.system.VMRuntime;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -88,9 +84,6 @@ public class GraphicsEnvironment {
|
|||||||
private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*";
|
private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*";
|
||||||
private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
|
private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
|
||||||
|
|
||||||
// ANGLE related properties.
|
|
||||||
private static final String ANGLE_RULES_FILE = "a4a_rules.json";
|
|
||||||
private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
|
|
||||||
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
|
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
|
||||||
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
|
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
|
||||||
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
|
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
|
||||||
@ -121,6 +114,7 @@ public class GraphicsEnvironment {
|
|||||||
private ClassLoader mClassLoader;
|
private ClassLoader mClassLoader;
|
||||||
private String mLibrarySearchPaths;
|
private String mLibrarySearchPaths;
|
||||||
private String mLibraryPermittedPaths;
|
private String mLibraryPermittedPaths;
|
||||||
|
private GameManager mGameManager;
|
||||||
|
|
||||||
private int mAngleOptInIndex = -1;
|
private int mAngleOptInIndex = -1;
|
||||||
|
|
||||||
@ -133,6 +127,8 @@ public class GraphicsEnvironment {
|
|||||||
final ApplicationInfo appInfoWithMetaData =
|
final ApplicationInfo appInfoWithMetaData =
|
||||||
getAppInfoWithMetadata(context, pm, packageName);
|
getAppInfoWithMetadata(context, pm, packageName);
|
||||||
|
|
||||||
|
mGameManager = context.getSystemService(GameManager.class);
|
||||||
|
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
|
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
|
||||||
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
|
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
|
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
|
||||||
@ -150,6 +146,23 @@ public class GraphicsEnvironment {
|
|||||||
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
|
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query to determine if the Game Mode has enabled ANGLE.
|
||||||
|
*/
|
||||||
|
private boolean isAngleEnabledByGameMode(Context context, String packageName) {
|
||||||
|
try {
|
||||||
|
final boolean gameModeEnabledAngle =
|
||||||
|
(mGameManager != null) && mGameManager.isAngleEnabled(packageName);
|
||||||
|
Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
|
||||||
|
return gameModeEnabledAngle;
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled "
|
||||||
|
+ "for package: " + packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query to determine if ANGLE should be used
|
* Query to determine if ANGLE should be used
|
||||||
*/
|
*/
|
||||||
@ -164,21 +177,16 @@ public class GraphicsEnvironment {
|
|||||||
Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
|
Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
|
||||||
+ "set to: '" + devOptIn + "'");
|
+ "set to: '" + devOptIn + "'");
|
||||||
|
|
||||||
// We only want to use ANGLE if the app is in the allowlist, or the developer has
|
// We only want to use ANGLE if the developer has explicitly chosen something other than
|
||||||
// explicitly chosen something other than default driver.
|
// default driver.
|
||||||
// The allowlist will be generated by the ANGLE APK at both boot time and
|
|
||||||
// ANGLE update time. It will only include apps mentioned in the rules file.
|
|
||||||
final boolean allowed = checkAngleAllowlist(context, coreSettings, packageName);
|
|
||||||
final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
|
final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
|
||||||
|
|
||||||
if (allowed) {
|
|
||||||
Log.v(TAG, "ANGLE allowlist includes " + packageName);
|
|
||||||
}
|
|
||||||
if (requested) {
|
if (requested) {
|
||||||
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
|
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return allowed || requested;
|
final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
|
||||||
|
|
||||||
|
return requested || gameModeEnabledAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getVulkanVersion(PackageManager pm) {
|
private int getVulkanVersion(PackageManager pm) {
|
||||||
@ -474,117 +482,6 @@ public class GraphicsEnvironment {
|
|||||||
return debugPackage;
|
return debugPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to setup ANGLE with a temporary rules file.
|
|
||||||
* True: Temporary rules file was loaded.
|
|
||||||
* False: Temporary rules file was *not* loaded.
|
|
||||||
*/
|
|
||||||
private boolean setupAngleWithTempRulesFile(Context context,
|
|
||||||
String packageName,
|
|
||||||
String paths,
|
|
||||||
String devOptIn) {
|
|
||||||
/**
|
|
||||||
* We only want to load a temp rules file for:
|
|
||||||
* - apps that are marked 'debuggable' in their manifest
|
|
||||||
* - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
|
|
||||||
* debugging (PR_SET_DUMPABLE).
|
|
||||||
*/
|
|
||||||
if (!isDebuggable()) {
|
|
||||||
Log.v(TAG, "Skipping loading temporary rules file");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(angleTempRules)) {
|
|
||||||
Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
|
|
||||||
|
|
||||||
final File tempRulesFile = new File(angleTempRules);
|
|
||||||
if (tempRulesFile.exists()) {
|
|
||||||
Log.i(TAG, angleTempRules + " exists, loading file.");
|
|
||||||
try {
|
|
||||||
final FileInputStream stream = new FileInputStream(angleTempRules);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final FileDescriptor rulesFd = stream.getFD();
|
|
||||||
final long rulesOffset = 0;
|
|
||||||
final long rulesLength = stream.getChannel().size();
|
|
||||||
Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
|
|
||||||
|
|
||||||
setAngleInfo(paths, packageName, devOptIn, null,
|
|
||||||
rulesFd, rulesOffset, rulesLength);
|
|
||||||
|
|
||||||
stream.close();
|
|
||||||
|
|
||||||
// We successfully setup ANGLE, so return with good status
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Log.w(TAG, "Temp ANGLE rules file not found: " + e);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
|
|
||||||
* True: APK rules file was loaded.
|
|
||||||
* False: APK rules file was *not* loaded.
|
|
||||||
*/
|
|
||||||
private boolean setupAngleRulesApk(String anglePkgName,
|
|
||||||
ApplicationInfo angleInfo,
|
|
||||||
PackageManager pm,
|
|
||||||
String packageName,
|
|
||||||
String paths,
|
|
||||||
String devOptIn,
|
|
||||||
String[] features) {
|
|
||||||
// Pass the rules file to loader for ANGLE decisions
|
|
||||||
try {
|
|
||||||
final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
|
|
||||||
|
|
||||||
try {
|
|
||||||
final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
|
|
||||||
|
|
||||||
setAngleInfo(paths, packageName, devOptIn, features, assetsFd.getFileDescriptor(),
|
|
||||||
assetsFd.getStartOffset(), assetsFd.getLength());
|
|
||||||
|
|
||||||
assetsFd.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
|
|
||||||
+ " from '" + anglePkgName + "': " + e);
|
|
||||||
}
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pull ANGLE allowlist from GlobalSettings and compare against current package
|
|
||||||
*/
|
|
||||||
private boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
|
|
||||||
final ContentResolver contentResolver = context.getContentResolver();
|
|
||||||
final List<String> angleAllowlist =
|
|
||||||
getGlobalSettingsString(contentResolver, bundle,
|
|
||||||
Settings.Global.ANGLE_ALLOWLIST);
|
|
||||||
|
|
||||||
if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist);
|
|
||||||
|
|
||||||
return angleAllowlist.contains(packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass ANGLE details down to trigger enable logic
|
* Pass ANGLE details down to trigger enable logic
|
||||||
*
|
*
|
||||||
@ -647,28 +544,21 @@ public class GraphicsEnvironment {
|
|||||||
|
|
||||||
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
|
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
|
||||||
|
|
||||||
// If the user has set the developer option to something other than default,
|
// We need to call setAngleInfo() with the package name and the developer option value
|
||||||
// we need to call setupAngleRulesApk() with the package name and the developer
|
//(native/angle/other). Then later when we are actually trying to load a driver,
|
||||||
// option value (native/angle/other). Then later when we are actually trying to
|
//GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
|
||||||
// load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before
|
//answer yes/no based on the previously set developer option value.
|
||||||
// and can confidently answer yes/no based on the previously set developer
|
final String devOptIn;
|
||||||
// option value.
|
final String[] features = getAngleEglFeatures(context, bundle);
|
||||||
final String devOptIn = getDriverForPackage(context, bundle, packageName);
|
final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
|
||||||
|
if (gameModeEnabledAngle) {
|
||||||
if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
|
devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
|
||||||
// We setup ANGLE with a temp rules file, so we're done here.
|
} else {
|
||||||
return true;
|
devOptIn = getDriverForPackage(context, bundle, packageName);
|
||||||
}
|
}
|
||||||
|
setAngleInfo(paths, packageName, devOptIn, features);
|
||||||
|
|
||||||
String[] features = getAngleEglFeatures(context, bundle);
|
return true;
|
||||||
|
|
||||||
if (setupAngleRulesApk(
|
|
||||||
anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
|
|
||||||
// ANGLE with rules is set up from the APK, hence return.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -956,7 +846,7 @@ public class GraphicsEnvironment {
|
|||||||
private static native void setGpuStats(String driverPackageName, String driverVersionName,
|
private static native void setGpuStats(String driverPackageName, String driverVersionName,
|
||||||
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
|
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
|
||||||
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
|
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
|
||||||
String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength);
|
String[] features);
|
||||||
private static native boolean getShouldUseAngle(String packageName);
|
private static native boolean getShouldUseAngle(String packageName);
|
||||||
private static native boolean setInjectLayersPrSetDumpable();
|
private static native boolean setInjectLayersPrSetDumpable();
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# Bug component: 554432
|
# Bug component: 554432
|
||||||
alexbuy@google.com
|
alexbuy@google.com
|
||||||
schfan@google.com
|
schfan@google.com
|
||||||
toddke@google.com
|
|
||||||
zyy@google.com
|
zyy@google.com
|
||||||
patb@google.com
|
patb@google.com
|
||||||
|
@ -18,6 +18,7 @@ package android.os.storage;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.UserIdInt;
|
||||||
import android.os.IVold;
|
import android.os.IVold;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -135,4 +136,19 @@ public abstract class StorageManagerInternal {
|
|||||||
* {@link VolumeInfo#isPrimary()}
|
* {@link VolumeInfo#isPrimary()}
|
||||||
*/
|
*/
|
||||||
public abstract List<String> getPrimaryVolumeIds();
|
public abstract List<String> getPrimaryVolumeIds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells StorageManager that CE storage for this user has been prepared.
|
||||||
|
*
|
||||||
|
* @param userId userId for which CE storage has been prepared
|
||||||
|
*/
|
||||||
|
public abstract void markCeStoragePrepared(@UserIdInt int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when CE storage for this user has been prepared.
|
||||||
|
*
|
||||||
|
* When the user key is unlocked and CE storage has been prepared,
|
||||||
|
* it's ok to access and modify CE directories on volumes for this user.
|
||||||
|
*/
|
||||||
|
public abstract boolean isCeStoragePrepared(@UserIdInt int userId);
|
||||||
}
|
}
|
||||||
|
@ -2241,6 +2241,21 @@ public final class Settings {
|
|||||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||||
public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS";
|
public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity Action: Show screen that lets user configure wifi tethering.
|
||||||
|
* <p>
|
||||||
|
* In some cases, a matching Activity may not exist, so ensure you safeguard against this.
|
||||||
|
* <p>
|
||||||
|
* Input: Nothing
|
||||||
|
* <p>
|
||||||
|
* Output: Nothing
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||||
|
public static final String ACTION_WIFI_TETHER_SETTING =
|
||||||
|
"com.android.settings.WIFI_TETHER_SETTINGS";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast to trigger notification of asking user to enable MMS.
|
* Broadcast to trigger notification of asking user to enable MMS.
|
||||||
* Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}.
|
* Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}.
|
||||||
@ -11844,6 +11859,12 @@ public final class Settings {
|
|||||||
@Readable
|
@Readable
|
||||||
public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed";
|
public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether UWB should be enabled.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final String UWB_ENABLED = "uwb_enabled";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value to specify whether network quality scores and badging should be shown in the UI.
|
* Value to specify whether network quality scores and badging should be shown in the UI.
|
||||||
*
|
*
|
||||||
@ -13669,13 +13690,6 @@ public final class Settings {
|
|||||||
public static final String ANGLE_GL_DRIVER_SELECTION_VALUES =
|
public static final String ANGLE_GL_DRIVER_SELECTION_VALUES =
|
||||||
"angle_gl_driver_selection_values";
|
"angle_gl_driver_selection_values";
|
||||||
|
|
||||||
/**
|
|
||||||
* List of package names that should check ANGLE rules
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@Readable
|
|
||||||
public static final String ANGLE_ALLOWLIST = "angle_allowlist";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists of ANGLE EGL features for debugging.
|
* Lists of ANGLE EGL features for debugging.
|
||||||
* Each list of features is separated by a comma, each feature in each list is separated by
|
* Each list of features is separated by a comma, each feature in each list is separated by
|
||||||
@ -14914,6 +14928,16 @@ public final class Settings {
|
|||||||
public static final String POWER_BUTTON_LONG_PRESS =
|
public static final String POWER_BUTTON_LONG_PRESS =
|
||||||
"power_button_long_press";
|
"power_button_long_press";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override internal R.integer.config_longPressOnPowerDurationMs. It determines the length
|
||||||
|
* of power button press to be considered a long press in milliseconds.
|
||||||
|
* Used by PhoneWindowManager.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@Readable
|
||||||
|
public static final String POWER_BUTTON_LONG_PRESS_DURATION_MS =
|
||||||
|
"power_button_long_press_duration_ms";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
|
* Overrides internal R.integer.config_veryLongPressOnPowerBehavior.
|
||||||
* Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
|
* Allowable values detailed in frameworks/base/core/res/res/values/config.xml.
|
||||||
|
@ -436,7 +436,7 @@ public class StatusBarNotification implements Parcelable {
|
|||||||
try {
|
try {
|
||||||
ApplicationInfo ai = context.getPackageManager()
|
ApplicationInfo ai = context.getPackageManager()
|
||||||
.getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
|
.getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
|
||||||
getUserId());
|
getNormalizedUserId());
|
||||||
mContext = context.createApplicationContext(ai,
|
mContext = context.createApplicationContext(ai,
|
||||||
Context.CONTEXT_RESTRICTED);
|
Context.CONTEXT_RESTRICTED);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
@ -24,7 +24,7 @@ import com.android.internal.os.IResultReceiver;
|
|||||||
/**
|
/**
|
||||||
* System-wide on-device translation service.
|
* System-wide on-device translation service.
|
||||||
*
|
*
|
||||||
* <p>Services requests to translate text between different languages. The primary use case for this
|
* <p>Services requests to translate data between different languages. The primary use case for this
|
||||||
* service is automatic translation of text and web views, when the auto Translate feature is
|
* service is automatic translation of text and web views, when the auto Translate feature is
|
||||||
* enabled.
|
* enabled.
|
||||||
*
|
*
|
||||||
|
@ -48,6 +48,7 @@ import android.view.translation.TranslationManager;
|
|||||||
import android.view.translation.TranslationRequest;
|
import android.view.translation.TranslationRequest;
|
||||||
import android.view.translation.TranslationResponse;
|
import android.view.translation.TranslationResponse;
|
||||||
import android.view.translation.TranslationSpec;
|
import android.view.translation.TranslationSpec;
|
||||||
|
import android.view.translation.Translator;
|
||||||
|
|
||||||
import com.android.internal.os.IResultReceiver;
|
import com.android.internal.os.IResultReceiver;
|
||||||
|
|
||||||
@ -81,7 +82,10 @@ public abstract class TranslationService extends Service {
|
|||||||
* android.R.styleable#TranslationService translation-service}></code> tag.
|
* android.R.styleable#TranslationService translation-service}></code> tag.
|
||||||
*
|
*
|
||||||
* <p>Here's an example of how to use it on {@code AndroidManifest.xml}:
|
* <p>Here's an example of how to use it on {@code AndroidManifest.xml}:
|
||||||
* TODO: fill in doc example (check CCService/AFService).
|
* <pre> <translation-service
|
||||||
|
* android:settingsActivity="foo.bar.SettingsActivity"
|
||||||
|
* . . .
|
||||||
|
* /></pre>
|
||||||
*/
|
*/
|
||||||
public static final String SERVICE_META_DATA = "android.translation_service";
|
public static final String SERVICE_META_DATA = "android.translation_service";
|
||||||
|
|
||||||
@ -148,7 +152,6 @@ public abstract class TranslationService extends Service {
|
|||||||
void onTranslationSuccess(@NonNull TranslationResponse response);
|
void onTranslationSuccess(@NonNull TranslationResponse response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: implement javadoc
|
|
||||||
* @removed use {@link #onTranslationSuccess} with an error response instead.
|
* @removed use {@link #onTranslationSuccess} with an error response instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@ -225,7 +228,7 @@ public abstract class TranslationService extends Service {
|
|||||||
* should call back with {@code false}.</p>
|
* should call back with {@code false}.</p>
|
||||||
*
|
*
|
||||||
* @param translationContext the {@link TranslationContext} of the session being created.
|
* @param translationContext the {@link TranslationContext} of the session being created.
|
||||||
* @param sessionId the int id of the session.
|
* @param sessionId the id of the session.
|
||||||
* @param callback {@link Consumer} to notify whether the session was successfully created.
|
* @param callback {@link Consumer} to notify whether the session was successfully created.
|
||||||
*/
|
*/
|
||||||
// TODO(b/176464808): the session id won't be unique cross client/server process. Need to find
|
// TODO(b/176464808): the session id won't be unique cross client/server process. Need to find
|
||||||
@ -234,8 +237,6 @@ public abstract class TranslationService extends Service {
|
|||||||
int sessionId, @NonNull Consumer<Boolean> callback);
|
int sessionId, @NonNull Consumer<Boolean> callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc.
|
|
||||||
*
|
|
||||||
* @removed use {@link #onCreateTranslationSession(TranslationContext, int, Consumer)}
|
* @removed use {@link #onCreateTranslationSession(TranslationContext, int, Consumer)}
|
||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
@ -246,19 +247,16 @@ public abstract class TranslationService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc.
|
* Called when a translation session is finished.
|
||||||
*
|
*
|
||||||
* @param sessionId
|
* <p>The translation session is finished when the client calls {@link Translator#destroy()} on
|
||||||
|
* the corresponding translator.
|
||||||
|
*
|
||||||
|
* @param sessionId id of the session that finished.
|
||||||
*/
|
*/
|
||||||
public abstract void onFinishTranslationSession(int sessionId);
|
public abstract void onFinishTranslationSession(int sessionId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc.
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param sessionId
|
|
||||||
* @param callback
|
|
||||||
* @param cancellationSignal
|
|
||||||
* @removed use
|
* @removed use
|
||||||
* {@link #onTranslationRequest(TranslationRequest, int, CancellationSignal, Consumer)} instead.
|
* {@link #onTranslationRequest(TranslationRequest, int, CancellationSignal, Consumer)} instead.
|
||||||
*/
|
*/
|
||||||
@ -276,23 +274,29 @@ public abstract class TranslationService extends Service {
|
|||||||
* {@link TranslationRequest#FLAG_PARTIAL_RESPONSES} was set, the service may call
|
* {@link TranslationRequest#FLAG_PARTIAL_RESPONSES} was set, the service may call
|
||||||
* {@code callback.accept()} multiple times with partial responses.</p>
|
* {@code callback.accept()} multiple times with partial responses.</p>
|
||||||
*
|
*
|
||||||
* @param request
|
* @param request The translation request containing the data to be translated.
|
||||||
* @param sessionId
|
* @param sessionId id of the session that sent the translation request.
|
||||||
* @param callback
|
* @param cancellationSignal A {@link CancellationSignal} that notifies when a client has
|
||||||
* @param cancellationSignal
|
* cancelled the operation in progress.
|
||||||
|
* @param callback {@link Consumer} to pass back the translation response.
|
||||||
*/
|
*/
|
||||||
public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
|
public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
|
||||||
@Nullable CancellationSignal cancellationSignal,
|
@Nullable CancellationSignal cancellationSignal,
|
||||||
@NonNull Consumer<TranslationResponse> callback);
|
@NonNull Consumer<TranslationResponse> callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc
|
* Called to request a set of {@link TranslationCapability}s that are supported by the service.
|
||||||
|
*
|
||||||
|
* <p>The set of translation capabilities are limited to those supporting the source and target
|
||||||
|
* {@link TranslationSpec.DataFormat}. e.g. Calling this with
|
||||||
|
* {@link TranslationSpec#DATA_FORMAT_TEXT} as source and target returns only capabilities that
|
||||||
|
* translates text to text.</p>
|
||||||
*
|
*
|
||||||
* <p>Must call {@code callback.accept} to pass back the set of translation capabilities.</p>
|
* <p>Must call {@code callback.accept} to pass back the set of translation capabilities.</p>
|
||||||
*
|
*
|
||||||
* @param sourceFormat
|
* @param sourceFormat data format restriction of the translation source spec.
|
||||||
* @param targetFormat
|
* @param targetFormat data format restriction of the translation target spec.
|
||||||
* @param callback
|
* @param callback {@link Consumer} to pass back the set of translation capabilities.
|
||||||
*/
|
*/
|
||||||
public abstract void onTranslationCapabilitiesRequest(
|
public abstract void onTranslationCapabilitiesRequest(
|
||||||
@TranslationSpec.DataFormat int sourceFormat,
|
@TranslationSpec.DataFormat int sourceFormat,
|
||||||
|
@ -96,6 +96,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -152,6 +153,7 @@ public abstract class WallpaperService extends Service {
|
|||||||
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
|
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
|
||||||
private static final int MSG_ZOOM = 10100;
|
private static final int MSG_ZOOM = 10100;
|
||||||
private static final int MSG_SCALE_PREVIEW = 10110;
|
private static final int MSG_SCALE_PREVIEW = 10110;
|
||||||
|
private static final int MSG_REPORT_SHOWN = 10150;
|
||||||
private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
|
private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
|
||||||
Float.NEGATIVE_INFINITY);
|
Float.NEGATIVE_INFINITY);
|
||||||
|
|
||||||
@ -526,6 +528,39 @@ public abstract class WallpaperService extends Service {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will be called in the end of {@link #updateSurface(boolean, boolean, boolean)}.
|
||||||
|
* If true is returned, the engine will not report shown until rendering finished is
|
||||||
|
* reported. Otherwise, the engine will report shown immediately right after redraw phase
|
||||||
|
* in {@link #updateSurface(boolean, boolean, boolean)}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean shouldWaitForEngineShown() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports the rendering is finished, stops waiting, then invokes
|
||||||
|
* {@link IWallpaperEngineWrapper#reportShown()}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void reportEngineShown(boolean waitForEngineShown) {
|
||||||
|
if (mIWallpaperEngine.mShownReported) return;
|
||||||
|
if (!waitForEngineShown) {
|
||||||
|
Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
|
||||||
|
mCaller.removeMessages(MSG_REPORT_SHOWN);
|
||||||
|
mCaller.sendMessage(message);
|
||||||
|
} else {
|
||||||
|
// if we are already waiting, no need to reset the timeout.
|
||||||
|
if (!mCaller.hasMessages(MSG_REPORT_SHOWN)) {
|
||||||
|
Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
|
||||||
|
mCaller.sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Control whether this wallpaper will receive raw touch events
|
* Control whether this wallpaper will receive raw touch events
|
||||||
* from the window manager as the user interacts with the window
|
* from the window manager as the user interacts with the window
|
||||||
@ -930,7 +965,7 @@ public abstract class WallpaperService extends Service {
|
|||||||
|
|
||||||
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
|
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
|
||||||
if (mDestroyed) {
|
if (mDestroyed) {
|
||||||
Log.w(TAG, "Ignoring updateSurface: destroyed");
|
Log.w(TAG, "Ignoring updateSurface due to destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean fixedSize = false;
|
boolean fixedSize = false;
|
||||||
@ -1197,7 +1232,6 @@ public abstract class WallpaperService extends Service {
|
|||||||
+ this);
|
+ this);
|
||||||
onVisibilityChanged(false);
|
onVisibilityChanged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
mIsCreating = false;
|
mIsCreating = false;
|
||||||
mSurfaceCreated = true;
|
mSurfaceCreated = true;
|
||||||
@ -1207,7 +1241,7 @@ public abstract class WallpaperService extends Service {
|
|||||||
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
|
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
|
||||||
}
|
}
|
||||||
reposition();
|
reposition();
|
||||||
mIWallpaperEngine.reportShown();
|
reportEngineShown(shouldWaitForEngineShown());
|
||||||
}
|
}
|
||||||
} catch (RemoteException ex) {
|
} catch (RemoteException ex) {
|
||||||
}
|
}
|
||||||
@ -2048,6 +2082,8 @@ public abstract class WallpaperService extends Service {
|
|||||||
mShownReported = true;
|
mShownReported = true;
|
||||||
try {
|
try {
|
||||||
mConnection.engineShown(this);
|
mConnection.engineShown(this);
|
||||||
|
Log.d(TAG, "Wallpaper has updated the surface:"
|
||||||
|
+ mWallpaperManager.getWallpaperInfo());
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(TAG, "Wallpaper host disappeared", e);
|
Log.w(TAG, "Wallpaper host disappeared", e);
|
||||||
return;
|
return;
|
||||||
@ -2201,6 +2237,9 @@ public abstract class WallpaperService extends Service {
|
|||||||
// Connection went away, nothing to do in here.
|
// Connection went away, nothing to do in here.
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case MSG_REPORT_SHOWN: {
|
||||||
|
reportShown();
|
||||||
|
} break;
|
||||||
default :
|
default :
|
||||||
Log.w(TAG, "Unknown message type " + message.what);
|
Log.w(TAG, "Unknown message type " + message.what);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ public abstract class RecognitionService extends Service {
|
|||||||
@NonNull AttributionSource attributionSource) {
|
@NonNull AttributionSource attributionSource) {
|
||||||
try {
|
try {
|
||||||
if (mCurrentCallback == null) {
|
if (mCurrentCallback == null) {
|
||||||
boolean preflightPermissionCheckPassed = checkPermissionForPreflight(
|
boolean preflightPermissionCheckPassed = checkPermissionForPreflightNotHardDenied(
|
||||||
attributionSource);
|
attributionSource);
|
||||||
if (preflightPermissionCheckPassed) {
|
if (preflightPermissionCheckPassed) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
@ -470,10 +470,11 @@ public abstract class RecognitionService extends Service {
|
|||||||
return mStartedDataDelivery;
|
return mStartedDataDelivery;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPermissionForPreflight(AttributionSource attributionSource) {
|
private boolean checkPermissionForPreflightNotHardDenied(AttributionSource attributionSource) {
|
||||||
return PermissionChecker.checkPermissionForPreflight(RecognitionService.this,
|
int result = PermissionChecker.checkPermissionForPreflight(RecognitionService.this,
|
||||||
Manifest.permission.RECORD_AUDIO, attributionSource)
|
Manifest.permission.RECORD_AUDIO, attributionSource);
|
||||||
== PermissionChecker.PERMISSION_GRANTED;
|
return result == PermissionChecker.PERMISSION_GRANTED
|
||||||
|
|| result == PermissionChecker.PERMISSION_SOFT_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishDataDelivery() {
|
void finishDataDelivery() {
|
||||||
|
@ -782,7 +782,7 @@ public class TextLine {
|
|||||||
|
|
||||||
int spanStart = runStart;
|
int spanStart = runStart;
|
||||||
int spanLimit;
|
int spanLimit;
|
||||||
if (mSpanned == null) {
|
if (mSpanned == null || runStart == runLimit) {
|
||||||
spanLimit = runLimit;
|
spanLimit = runLimit;
|
||||||
} else {
|
} else {
|
||||||
int target = after ? offset + 1 : offset;
|
int target = after ? offset + 1 : offset;
|
||||||
|
@ -62,6 +62,13 @@ public class TranslationTransformationMethod implements TransformationMethod2 {
|
|||||||
return mOriginalTranslationMethod;
|
return mOriginalTranslationMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link TextView}'s {@link ViewTranslationResponse}.
|
||||||
|
*/
|
||||||
|
public ViewTranslationResponse getViewTranslationResponse() {
|
||||||
|
return mTranslationResponse;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getTransformation(CharSequence source, View view) {
|
public CharSequence getTransformation(CharSequence source, View view) {
|
||||||
if (!mAllowLengthChanges) {
|
if (!mAllowLengthChanges) {
|
||||||
|
@ -814,9 +814,10 @@ interface IWindowManager
|
|||||||
* @param displayId The display associated with the window context
|
* @param displayId The display associated with the window context
|
||||||
* @param options A bundle used to pass window-related options and choose the right DisplayArea
|
* @param options A bundle used to pass window-related options and choose the right DisplayArea
|
||||||
*
|
*
|
||||||
* @return {@code true} if the WindowContext is attached to the DisplayArea successfully.
|
* @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is
|
||||||
|
* attached to the DisplayArea successfully. {@code null}, otherwise.
|
||||||
*/
|
*/
|
||||||
boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
|
Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId,
|
||||||
in Bundle options);
|
in Bundle options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,6 +53,10 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private String mWindowTitle = null;
|
private String mWindowTitle = null;
|
||||||
|
|
||||||
|
/** The package which owns the window. */
|
||||||
|
@Nullable
|
||||||
|
private String mPackageName = null;
|
||||||
|
|
||||||
/** Carries additional logging and debugging information when enabled. */
|
/** Carries additional logging and debugging information when enabled. */
|
||||||
@NonNull
|
@NonNull
|
||||||
@DataClass.PluralOf("message")
|
@DataClass.PluralOf("message")
|
||||||
@ -77,7 +81,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Code below generated by codegen v1.0.22.
|
// Code below generated by codegen v1.0.23.
|
||||||
//
|
//
|
||||||
// DO NOT MODIFY!
|
// DO NOT MODIFY!
|
||||||
// CHECKSTYLE:OFF Generated code
|
// CHECKSTYLE:OFF Generated code
|
||||||
@ -97,6 +101,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
@Nullable Rect windowBounds,
|
@Nullable Rect windowBounds,
|
||||||
@Nullable Rect boundsInWindow,
|
@Nullable Rect boundsInWindow,
|
||||||
@Nullable String windowTitle,
|
@Nullable String windowTitle,
|
||||||
|
@Nullable String packageName,
|
||||||
@NonNull ArrayList<String> messages) {
|
@NonNull ArrayList<String> messages) {
|
||||||
this.mDescription = description;
|
this.mDescription = description;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
@ -105,6 +110,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
this.mWindowBounds = windowBounds;
|
this.mWindowBounds = windowBounds;
|
||||||
this.mBoundsInWindow = boundsInWindow;
|
this.mBoundsInWindow = boundsInWindow;
|
||||||
this.mWindowTitle = windowTitle;
|
this.mWindowTitle = windowTitle;
|
||||||
|
this.mPackageName = packageName;
|
||||||
this.mMessages = messages;
|
this.mMessages = messages;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
NonNull.class, null, mMessages);
|
NonNull.class, null, mMessages);
|
||||||
@ -152,6 +158,14 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
return mWindowTitle;
|
return mWindowTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The package name of the process the window is owned by.
|
||||||
|
*/
|
||||||
|
@DataClass.Generated.Member
|
||||||
|
public @Nullable String getPackageName() {
|
||||||
|
return mPackageName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Carries additional logging and debugging information when enabled.
|
* Carries additional logging and debugging information when enabled.
|
||||||
*/
|
*/
|
||||||
@ -172,6 +186,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
"windowBounds = " + mWindowBounds + ", " +
|
"windowBounds = " + mWindowBounds + ", " +
|
||||||
"boundsInWindow = " + mBoundsInWindow + ", " +
|
"boundsInWindow = " + mBoundsInWindow + ", " +
|
||||||
"windowTitle = " + mWindowTitle + ", " +
|
"windowTitle = " + mWindowTitle + ", " +
|
||||||
|
"packageName = " + mPackageName + ", " +
|
||||||
"messages = " + mMessages +
|
"messages = " + mMessages +
|
||||||
" }";
|
" }";
|
||||||
}
|
}
|
||||||
@ -187,12 +202,14 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
if (mWindowBounds != null) flg |= 0x4;
|
if (mWindowBounds != null) flg |= 0x4;
|
||||||
if (mBoundsInWindow != null) flg |= 0x8;
|
if (mBoundsInWindow != null) flg |= 0x8;
|
||||||
if (mWindowTitle != null) flg |= 0x10;
|
if (mWindowTitle != null) flg |= 0x10;
|
||||||
|
if (mPackageName != null) flg |= 0x20;
|
||||||
dest.writeByte(flg);
|
dest.writeByte(flg);
|
||||||
dest.writeString(mDescription);
|
dest.writeString(mDescription);
|
||||||
if (mConnection != null) dest.writeStrongInterface(mConnection);
|
if (mConnection != null) dest.writeStrongInterface(mConnection);
|
||||||
if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
|
if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
|
||||||
if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
|
if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
|
||||||
if (mWindowTitle != null) dest.writeString(mWindowTitle);
|
if (mWindowTitle != null) dest.writeString(mWindowTitle);
|
||||||
|
if (mPackageName != null) dest.writeString(mPackageName);
|
||||||
dest.writeStringList(mMessages);
|
dest.writeStringList(mMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +230,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
|
Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
|
||||||
Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
|
Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
|
||||||
String windowTitle = (flg & 0x10) == 0 ? null : in.readString();
|
String windowTitle = (flg & 0x10) == 0 ? null : in.readString();
|
||||||
|
String packageName = (flg & 0x20) == 0 ? null : in.readString();
|
||||||
ArrayList<String> messages = new ArrayList<>();
|
ArrayList<String> messages = new ArrayList<>();
|
||||||
in.readStringList(messages);
|
in.readStringList(messages);
|
||||||
|
|
||||||
@ -223,6 +241,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
this.mWindowBounds = windowBounds;
|
this.mWindowBounds = windowBounds;
|
||||||
this.mBoundsInWindow = boundsInWindow;
|
this.mBoundsInWindow = boundsInWindow;
|
||||||
this.mWindowTitle = windowTitle;
|
this.mWindowTitle = windowTitle;
|
||||||
|
this.mPackageName = packageName;
|
||||||
this.mMessages = messages;
|
this.mMessages = messages;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
NonNull.class, null, mMessages);
|
NonNull.class, null, mMessages);
|
||||||
@ -256,6 +275,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
private @Nullable Rect mWindowBounds;
|
private @Nullable Rect mWindowBounds;
|
||||||
private @Nullable Rect mBoundsInWindow;
|
private @Nullable Rect mBoundsInWindow;
|
||||||
private @Nullable String mWindowTitle;
|
private @Nullable String mWindowTitle;
|
||||||
|
private @Nullable String mPackageName;
|
||||||
private @NonNull ArrayList<String> mMessages;
|
private @NonNull ArrayList<String> mMessages;
|
||||||
|
|
||||||
private long mBuilderFieldsSet = 0L;
|
private long mBuilderFieldsSet = 0L;
|
||||||
@ -318,13 +338,24 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The package name of the process the window is owned by.
|
||||||
|
*/
|
||||||
|
@DataClass.Generated.Member
|
||||||
|
public @NonNull Builder setPackageName(@NonNull String value) {
|
||||||
|
checkNotUsed();
|
||||||
|
mBuilderFieldsSet |= 0x20;
|
||||||
|
mPackageName = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Carries additional logging and debugging information when enabled.
|
* Carries additional logging and debugging information when enabled.
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
|
public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
|
||||||
checkNotUsed();
|
checkNotUsed();
|
||||||
mBuilderFieldsSet |= 0x20;
|
mBuilderFieldsSet |= 0x40;
|
||||||
mMessages = value;
|
mMessages = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -340,7 +371,7 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
/** Builds the instance. This builder should not be touched after calling this! */
|
/** Builds the instance. This builder should not be touched after calling this! */
|
||||||
public @NonNull ScrollCaptureResponse build() {
|
public @NonNull ScrollCaptureResponse build() {
|
||||||
checkNotUsed();
|
checkNotUsed();
|
||||||
mBuilderFieldsSet |= 0x40; // Mark builder used
|
mBuilderFieldsSet |= 0x80; // Mark builder used
|
||||||
|
|
||||||
if ((mBuilderFieldsSet & 0x1) == 0) {
|
if ((mBuilderFieldsSet & 0x1) == 0) {
|
||||||
mDescription = "";
|
mDescription = "";
|
||||||
@ -358,6 +389,9 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
mWindowTitle = null;
|
mWindowTitle = null;
|
||||||
}
|
}
|
||||||
if ((mBuilderFieldsSet & 0x20) == 0) {
|
if ((mBuilderFieldsSet & 0x20) == 0) {
|
||||||
|
mPackageName = null;
|
||||||
|
}
|
||||||
|
if ((mBuilderFieldsSet & 0x40) == 0) {
|
||||||
mMessages = new ArrayList<>();
|
mMessages = new ArrayList<>();
|
||||||
}
|
}
|
||||||
ScrollCaptureResponse o = new ScrollCaptureResponse(
|
ScrollCaptureResponse o = new ScrollCaptureResponse(
|
||||||
@ -366,12 +400,13 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
mWindowBounds,
|
mWindowBounds,
|
||||||
mBoundsInWindow,
|
mBoundsInWindow,
|
||||||
mWindowTitle,
|
mWindowTitle,
|
||||||
|
mPackageName,
|
||||||
mMessages);
|
mMessages);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNotUsed() {
|
private void checkNotUsed() {
|
||||||
if ((mBuilderFieldsSet & 0x40) != 0) {
|
if ((mBuilderFieldsSet & 0x80) != 0) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"This Builder should not be reused. Use a new Builder instance instead");
|
"This Builder should not be reused. Use a new Builder instance instead");
|
||||||
}
|
}
|
||||||
@ -379,10 +414,10 @@ public class ScrollCaptureResponse implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DataClass.Generated(
|
@DataClass.Generated(
|
||||||
time = 1614833185795L,
|
time = 1628630366187L,
|
||||||
codegenVersion = "1.0.22",
|
codegenVersion = "1.0.23",
|
||||||
sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java",
|
sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java",
|
||||||
inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic boolean isConnected()\npublic void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
|
inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic boolean isConnected()\npublic void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private void __metadata() {}
|
private void __metadata() {}
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ public class Surface implements Parcelable {
|
|||||||
|
|
||||||
private static native int nativeSetFrameRate(
|
private static native int nativeSetFrameRate(
|
||||||
long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
|
long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
|
||||||
|
private static native void nativeDestroy(long nativeObject);
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
|
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
|
||||||
new Parcelable.Creator<Surface>() {
|
new Parcelable.Creator<Surface>() {
|
||||||
@ -339,6 +340,9 @@ public class Surface implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
if (mNativeObject != 0) {
|
||||||
|
nativeDestroy(mNativeObject);
|
||||||
|
}
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
|||||||
mSurfaceAlpha = 1f;
|
mSurfaceAlpha = 1f;
|
||||||
|
|
||||||
synchronized (mSurfaceControlLock) {
|
synchronized (mSurfaceControlLock) {
|
||||||
mSurface.release();
|
mSurface.destroy();
|
||||||
if (mBlastBufferQueue != null) {
|
if (mBlastBufferQueue != null) {
|
||||||
mBlastBufferQueue.destroy();
|
mBlastBufferQueue.destroy();
|
||||||
mBlastBufferQueue = null;
|
mBlastBufferQueue = null;
|
||||||
|
@ -20830,13 +20830,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
|||||||
mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;
|
mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
|
||||||
|
|
||||||
mAttachInfo = null;
|
mAttachInfo = null;
|
||||||
if (mOverlay != null) {
|
if (mOverlay != null) {
|
||||||
mOverlay.getOverlayView().dispatchDetachedFromWindow();
|
mOverlay.getOverlayView().dispatchDetachedFromWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyEnterOrExitForAutoFillIfNeeded(false);
|
notifyEnterOrExitForAutoFillIfNeeded(false);
|
||||||
notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2836,8 +2836,13 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean surfaceControlChanged =
|
||||||
|
(relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
|
||||||
|
== RELAYOUT_RES_SURFACE_CHANGED;
|
||||||
|
|
||||||
if (mSurfaceControl.isValid()) {
|
if (mSurfaceControl.isValid()) {
|
||||||
updateOpacity(mWindowAttributes, dragResizing);
|
updateOpacity(mWindowAttributes, dragResizing,
|
||||||
|
surfaceControlChanged /*forceUpdate */);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
|
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
|
||||||
@ -2872,9 +2877,7 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
|
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
|
||||||
// SurfaceControl.
|
// SurfaceControl.
|
||||||
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
|
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
|
||||||
|| (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
|
|| surfaceControlChanged) && mSurface.isValid();
|
||||||
== RELAYOUT_RES_SURFACE_CHANGED)
|
|
||||||
&& mSurface.isValid();
|
|
||||||
if (surfaceReplaced) {
|
if (surfaceReplaced) {
|
||||||
mSurfaceSequenceId++;
|
mSurfaceSequenceId++;
|
||||||
}
|
}
|
||||||
@ -7824,7 +7827,8 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
return relayoutResult;
|
return relayoutResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing) {
|
private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
|
||||||
|
boolean forceUpdate) {
|
||||||
boolean opaque = false;
|
boolean opaque = false;
|
||||||
|
|
||||||
if (!PixelFormat.formatHasAlpha(params.format)
|
if (!PixelFormat.formatHasAlpha(params.format)
|
||||||
@ -7840,7 +7844,7 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
opaque = true;
|
opaque = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsSurfaceOpaque == opaque) {
|
if (!forceUpdate && mIsSurfaceOpaque == opaque) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9493,6 +9497,7 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
|
|
||||||
ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
|
ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
|
||||||
response.setWindowTitle(getTitle().toString());
|
response.setWindowTitle(getTitle().toString());
|
||||||
|
response.setPackageName(mContext.getPackageName());
|
||||||
|
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
IndentingPrintWriter pw = new IndentingPrintWriter(writer);
|
IndentingPrintWriter pw = new IndentingPrintWriter(writer);
|
||||||
|
@ -57,6 +57,9 @@ public class TranslateAnimation extends Animation {
|
|||||||
/** @hide */
|
/** @hide */
|
||||||
protected float mToYDelta;
|
protected float mToYDelta;
|
||||||
|
|
||||||
|
private int mWidth;
|
||||||
|
private int mParentWidth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor used when a TranslateAnimation is loaded from a resource.
|
* Constructor used when a TranslateAnimation is loaded from a resource.
|
||||||
*
|
*
|
||||||
@ -179,5 +182,60 @@ public class TranslateAnimation extends Animation {
|
|||||||
mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
|
mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
|
||||||
mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
|
mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
|
||||||
mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
|
mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
|
||||||
|
|
||||||
|
mWidth = width;
|
||||||
|
mParentWidth = parentWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether or not the translation is exclusively an x axis translation.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isXAxisTransition() {
|
||||||
|
return mFromXDelta - mToXDelta != 0 && mFromYDelta - mToYDelta == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether or not the translation is a full width x axis slide in or out translation.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isFullWidthTranslate() {
|
||||||
|
boolean isXAxisSlideTransition =
|
||||||
|
isSlideInLeft() || isSlideOutRight() || isSlideInRight() || isSlideOutLeft();
|
||||||
|
return mWidth == mParentWidth && isXAxisSlideTransition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSlideInLeft() {
|
||||||
|
boolean startsOutOfParentOnLeft = mFromXDelta <= -mWidth;
|
||||||
|
return startsOutOfParentOnLeft && endsXEnclosedWithinParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSlideOutRight() {
|
||||||
|
boolean endOutOfParentOnRight = mToXDelta >= mParentWidth;
|
||||||
|
return startsXEnclosedWithinParent() && endOutOfParentOnRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSlideInRight() {
|
||||||
|
boolean startsOutOfParentOnRight = mFromXDelta >= mParentWidth;
|
||||||
|
return startsOutOfParentOnRight && endsXEnclosedWithinParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSlideOutLeft() {
|
||||||
|
boolean endOutOfParentOnLeft = mToXDelta <= -mWidth;
|
||||||
|
return startsXEnclosedWithinParent() && endOutOfParentOnLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean endsXEnclosedWithinParent() {
|
||||||
|
return mWidth <= mParentWidth
|
||||||
|
&& mToXDelta + mWidth <= mParentWidth
|
||||||
|
&& mToXDelta >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean startsXEnclosedWithinParent() {
|
||||||
|
return mWidth <= mParentWidth
|
||||||
|
&& mFromXDelta + mWidth <= mParentWidth
|
||||||
|
&& mFromXDelta >= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,15 +40,18 @@ import java.util.function.Consumer;
|
|||||||
public final class TranslationCapability implements Parcelable {
|
public final class TranslationCapability implements Parcelable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc
|
* The translation service supports translation between the source and target specs, and it is
|
||||||
|
* ready to be downloaded onto the device.
|
||||||
*/
|
*/
|
||||||
public static final @ModelState int STATE_AVAILABLE_TO_DOWNLOAD = 1;
|
public static final @ModelState int STATE_AVAILABLE_TO_DOWNLOAD = 1;
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc
|
* The translation service supports translation between the source and target specs, and it is
|
||||||
|
* being downloaded onto the device currently.
|
||||||
*/
|
*/
|
||||||
public static final @ModelState int STATE_DOWNLOADING = 2;
|
public static final @ModelState int STATE_DOWNLOADING = 2;
|
||||||
/**
|
/**
|
||||||
* TODO: fill in javadoc
|
* The translation service supports translation between the source and target specs, and it is
|
||||||
|
* downloaded and ready to use on device.
|
||||||
*/
|
*/
|
||||||
public static final @ModelState int STATE_ON_DEVICE = 3;
|
public static final @ModelState int STATE_ON_DEVICE = 3;
|
||||||
/**
|
/**
|
||||||
@ -305,7 +308,7 @@ public final class TranslationCapability implements Parcelable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@DataClass.Generated(
|
@DataClass.Generated(
|
||||||
time = 1624307114468L,
|
time = 1629158466039L,
|
||||||
codegenVersion = "1.0.23",
|
codegenVersion = "1.0.23",
|
||||||
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationCapability.java",
|
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationCapability.java",
|
||||||
inputSignatures = "public static final @android.view.translation.TranslationCapability.ModelState int STATE_AVAILABLE_TO_DOWNLOAD\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_DOWNLOADING\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_ON_DEVICE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_NOT_AVAILABLE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_REMOVED_AND_AVAILABLE\nprivate final @android.view.translation.TranslationCapability.ModelState int mState\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mTargetSpec\nprivate final boolean mUiTranslationEnabled\nprivate final @android.view.translation.TranslationContext.TranslationFlag int mSupportedTranslationFlags\nclass TranslationCapability extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstDefs=true, genToString=true, genConstructor=false)")
|
inputSignatures = "public static final @android.view.translation.TranslationCapability.ModelState int STATE_AVAILABLE_TO_DOWNLOAD\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_DOWNLOADING\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_ON_DEVICE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_NOT_AVAILABLE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_REMOVED_AND_AVAILABLE\nprivate final @android.view.translation.TranslationCapability.ModelState int mState\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mTargetSpec\nprivate final boolean mUiTranslationEnabled\nprivate final @android.view.translation.TranslationContext.TranslationFlag int mSupportedTranslationFlags\nclass TranslationCapability extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstDefs=true, genToString=true, genConstructor=false)")
|
||||||
|
@ -39,12 +39,16 @@ public final class TranslationRequest implements Parcelable {
|
|||||||
public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1;
|
public static final @RequestFlags int FLAG_TRANSLATION_RESULT = 0x1;
|
||||||
/**
|
/**
|
||||||
* Indicates this request wants to receive the dictionary result.
|
* Indicates this request wants to receive the dictionary result.
|
||||||
* TODO: describe the structure of the result.
|
*
|
||||||
|
* <p>See {@link TranslationResponseValue#EXTRA_DEFINITIONS} for more detail on the structure
|
||||||
|
* of the returned data.
|
||||||
*/
|
*/
|
||||||
public static final @RequestFlags int FLAG_DICTIONARY_RESULT = 0x2;
|
public static final @RequestFlags int FLAG_DICTIONARY_RESULT = 0x2;
|
||||||
/**
|
/**
|
||||||
* Indicates this request wants to receive the transliteration result.
|
* Indicates this request wants to receive the transliteration result.
|
||||||
* TODO: describe the structure of the result.
|
*
|
||||||
|
* <p>This returns a CharSequence representation of the transliteration of the translated text.
|
||||||
|
* See {@link TranslationResponseValue#getTransliteration()}.
|
||||||
*/
|
*/
|
||||||
public static final @RequestFlags int FLAG_TRANSLITERATION_RESULT = 0x4;
|
public static final @RequestFlags int FLAG_TRANSLITERATION_RESULT = 0x4;
|
||||||
/**
|
/**
|
||||||
@ -327,7 +331,8 @@ public final class TranslationRequest implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see #setTranslationRequestValues
|
/**
|
||||||
|
* @see #setTranslationRequestValues
|
||||||
* @removed
|
* @removed
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
@ -352,7 +357,8 @@ public final class TranslationRequest implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see #setViewTranslationRequests
|
/**
|
||||||
|
* @see #setViewTranslationRequests
|
||||||
* @removed
|
* @removed
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
@ -394,7 +400,7 @@ public final class TranslationRequest implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DataClass.Generated(
|
@DataClass.Generated(
|
||||||
time = 1620429997487L,
|
time = 1629159107226L,
|
||||||
codegenVersion = "1.0.23",
|
codegenVersion = "1.0.23",
|
||||||
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java",
|
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java",
|
||||||
inputSignatures = "public static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_DICTIONARY_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLITERATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_PARTIAL_RESPONSES\nprivate final @android.view.translation.TranslationRequest.RequestFlags int mFlags\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.List<android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"viewTranslationRequest\") java.util.List<android.view.translation.ViewTranslationRequest> mViewTranslationRequests\nprivate static int defaultFlags()\nprivate static java.util.List<android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nprivate static java.util.List<android.view.translation.ViewTranslationRequest> defaultViewTranslationRequests()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addTranslationRequestValue(android.view.translation.TranslationRequestValue)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addViewTranslationRequest(android.view.translation.ViewTranslationRequest)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genBuilder=true)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addTranslationRequestValue(android.view.translation.TranslationRequestValue)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addViewTranslationRequest(android.view.translation.ViewTranslationRequest)\nclass BaseBuilder extends java.lang.Object implements []")
|
inputSignatures = "public static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_DICTIONARY_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_TRANSLITERATION_RESULT\npublic static final @android.view.translation.TranslationRequest.RequestFlags int FLAG_PARTIAL_RESPONSES\nprivate final @android.view.translation.TranslationRequest.RequestFlags int mFlags\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.List<android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"viewTranslationRequest\") java.util.List<android.view.translation.ViewTranslationRequest> mViewTranslationRequests\nprivate static int defaultFlags()\nprivate static java.util.List<android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nprivate static java.util.List<android.view.translation.ViewTranslationRequest> defaultViewTranslationRequests()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addTranslationRequestValue(android.view.translation.TranslationRequestValue)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addViewTranslationRequest(android.view.translation.ViewTranslationRequest)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genBuilder=true)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addTranslationRequestValue(android.view.translation.TranslationRequestValue)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationRequest.Builder addViewTranslationRequest(android.view.translation.ViewTranslationRequest)\nclass BaseBuilder extends java.lang.Object implements []")
|
||||||
|
@ -93,9 +93,11 @@ public final class TranslationResponseValue implements Parcelable {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final Bundle mExtras;
|
private final Bundle mExtras;
|
||||||
|
|
||||||
|
// TODO: Add example of transliteration.
|
||||||
/**
|
/**
|
||||||
* The transliteration result of the translated text.
|
* The transliteration result of the translated text.
|
||||||
* TODO: Describe the result structure.
|
*
|
||||||
|
* <p>This returns a CharSequence representation of the transliteration of the translated text.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private final CharSequence mTransliteration;
|
private final CharSequence mTransliteration;
|
||||||
@ -223,7 +225,8 @@ public final class TranslationResponseValue implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The transliteration result of the translated text.
|
* The transliteration result of the translated text.
|
||||||
* TODO: Describe the result structure.
|
*
|
||||||
|
* <p>This returns a CharSequence representation of the transliteration of the translated text.
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
public @Nullable CharSequence getTransliteration() {
|
public @Nullable CharSequence getTransliteration() {
|
||||||
@ -407,7 +410,8 @@ public final class TranslationResponseValue implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The transliteration result of the translated text.
|
* The transliteration result of the translated text.
|
||||||
* TODO: Describe the result structure.
|
*
|
||||||
|
* <p>This returns a CharSequence representation of the transliteration of the translated text.
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
public @NonNull Builder setTransliteration(@NonNull CharSequence value) {
|
public @NonNull Builder setTransliteration(@NonNull CharSequence value) {
|
||||||
@ -448,7 +452,7 @@ public final class TranslationResponseValue implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DataClass.Generated(
|
@DataClass.Generated(
|
||||||
time = 1622133051937L,
|
time = 1631057245846L,
|
||||||
codegenVersion = "1.0.23",
|
codegenVersion = "1.0.23",
|
||||||
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java",
|
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java",
|
||||||
inputSignatures = "public static final int STATUS_SUCCESS\npublic static final int STATUS_ERROR\npublic static final java.lang.String EXTRA_DEFINITIONS\nprivate final @android.view.translation.TranslationResponseValue.Status int mStatusCode\nprivate final @android.annotation.Nullable java.lang.CharSequence mText\nprivate final @android.annotation.NonNull android.os.Bundle mExtras\nprivate final @android.annotation.Nullable java.lang.CharSequence mTransliteration\npublic static @android.annotation.NonNull android.view.translation.TranslationResponseValue forError()\nprivate static java.lang.CharSequence defaultText()\nprivate static android.os.Bundle defaultExtras()\nprivate boolean extrasEquals(android.os.Bundle)\nprivate static java.lang.CharSequence defaultTransliteration()\nclass TranslationResponseValue extends java.lang.Object implements [android.os.Parcelable]\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)\nclass BaseBuilder extends java.lang.Object implements []")
|
inputSignatures = "public static final int STATUS_SUCCESS\npublic static final int STATUS_ERROR\npublic static final java.lang.String EXTRA_DEFINITIONS\nprivate final @android.view.translation.TranslationResponseValue.Status int mStatusCode\nprivate final @android.annotation.Nullable java.lang.CharSequence mText\nprivate final @android.annotation.NonNull android.os.Bundle mExtras\nprivate final @android.annotation.Nullable java.lang.CharSequence mTransliteration\npublic static @android.annotation.NonNull android.view.translation.TranslationResponseValue forError()\nprivate static java.lang.CharSequence defaultText()\nprivate static android.os.Bundle defaultExtras()\nprivate boolean extrasEquals(android.os.Bundle)\nprivate static java.lang.CharSequence defaultTransliteration()\nclass TranslationResponseValue extends java.lang.Object implements [android.os.Parcelable]\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)\nclass BaseBuilder extends java.lang.Object implements []")
|
||||||
|
@ -356,7 +356,11 @@ public class UiTranslationController {
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < translatedResult.size(); i++) {
|
for (int i = 0; i < translatedResult.size(); i++) {
|
||||||
final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i));
|
final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i));
|
||||||
final View view = mViews.get(autofillId).get();
|
final WeakReference<View> viewRef = mViews.get(autofillId);
|
||||||
|
if (viewRef == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final View view = viewRef.get();
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
|
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
|
||||||
+ " may be gone.");
|
+ " may be gone.");
|
||||||
@ -416,22 +420,30 @@ public class UiTranslationController {
|
|||||||
Log.w(TAG, "No AutofillId is set in ViewTranslationResponse");
|
Log.w(TAG, "No AutofillId is set in ViewTranslationResponse");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final View view = mViews.get(autofillId).get();
|
final WeakReference<View> viewRef = mViews.get(autofillId);
|
||||||
|
if (viewRef == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final View view = viewRef.get();
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
|
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
|
||||||
+ " may be gone.");
|
+ " may be gone.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mActivity.runOnUiThread(() -> {
|
mActivity.runOnUiThread(() -> {
|
||||||
|
ViewTranslationCallback callback = view.getViewTranslationCallback();
|
||||||
if (view.getViewTranslationResponse() != null
|
if (view.getViewTranslationResponse() != null
|
||||||
&& view.getViewTranslationResponse().equals(response)) {
|
&& view.getViewTranslationResponse().equals(response)) {
|
||||||
if (DEBUG) {
|
if (callback instanceof TextViewTranslationCallback) {
|
||||||
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
|
if (((TextViewTranslationCallback) callback).isShowingTranslation()) {
|
||||||
+ ". Ignoring.");
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
|
||||||
|
+ ". Ignoring.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
ViewTranslationCallback callback = view.getViewTranslationCallback();
|
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
if (view instanceof TextView) {
|
if (view instanceof TextView) {
|
||||||
// developer doesn't provide their override, we set the default TextView
|
// developer doesn't provide their override, we set the default TextView
|
||||||
@ -590,9 +602,8 @@ public class UiTranslationController {
|
|||||||
final View rootView = roots.get(rootNum).getView();
|
final View rootView = roots.get(rootNum).getView();
|
||||||
if (rootView instanceof ViewGroup) {
|
if (rootView instanceof ViewGroup) {
|
||||||
findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds);
|
findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds);
|
||||||
} else {
|
|
||||||
addViewIfNeeded(sourceViewIds, rootView);
|
|
||||||
}
|
}
|
||||||
|
addViewIfNeeded(sourceViewIds, rootView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,9 +614,8 @@ public class UiTranslationController {
|
|||||||
final View child = viewGroup.getChildAt(i);
|
final View child = viewGroup.getChildAt(i);
|
||||||
if (child instanceof ViewGroup) {
|
if (child instanceof ViewGroup) {
|
||||||
findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds);
|
findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds);
|
||||||
} else {
|
|
||||||
addViewIfNeeded(sourceViewIds, child);
|
|
||||||
}
|
}
|
||||||
|
addViewIfNeeded(sourceViewIds, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import android.util.ArrayMap;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.autofill.AutofillId;
|
import android.view.autofill.AutofillId;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
|
||||||
@ -42,11 +43,50 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
// TODO(b/178044703): Describe what UI Translation is.
|
|
||||||
/**
|
/**
|
||||||
* The {@link UiTranslationManager} class provides ways for apps to use the ui translation
|
* <p>The {@link UiTranslationManager} class provides ways for apps to use the ui translation
|
||||||
* function in framework.
|
* function in framework.
|
||||||
|
*
|
||||||
|
* <p> The UI translation provides ways for apps to support inline translation for the views. For
|
||||||
|
* example the system supports text translation for {@link TextView}. To support UI translation for
|
||||||
|
* your views, you should override the following methods to provide the content to be translated
|
||||||
|
* and deal with the translated result. Here is an example for {@link TextView}-like views:
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* public class MyTextView extends View {
|
||||||
|
* public MyTextView(...) {
|
||||||
|
* // implements how to show the translated result in your View in
|
||||||
|
* // ViewTranslationCallback and set it by setViewTranslationCallback()
|
||||||
|
* setViewTranslationCallback(new MyViewTranslationCallback());
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public void onCreateViewTranslationRequest(int[] supportedFormats,
|
||||||
|
* Consumer<ViewTranslationRequest> requestsCollector) {
|
||||||
|
* // collect the information that needs to be translated
|
||||||
|
* ViewTranslationRequest.Builder requestBuilder =
|
||||||
|
* new ViewTranslationRequest.Builder(getAutofillId());
|
||||||
|
* requestBuilder.setValue(ViewTranslationRequest.ID_TEXT,
|
||||||
|
* TranslationRequestValue.forText(etText()));
|
||||||
|
* requestsCollector.accept(requestBuilder.build());
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public void onProvideContentCaptureStructure(
|
||||||
|
* ViewStructure structure, int flags) {
|
||||||
|
* // set ViewTranslationResponse
|
||||||
|
* super.onViewTranslationResponse(response);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code></pre>
|
||||||
|
*
|
||||||
|
* <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws the
|
||||||
|
* HTML using {@link android.graphics.Canvas} or native libraries in a different render process),
|
||||||
|
* you must override {@link View#onCreateVirtualViewTranslationRequests(long[], int[], Consumer)} to
|
||||||
|
* provide the content to be translated and implement
|
||||||
|
* {@link View#onVirtualViewTranslationResponses(android.util.LongSparseArray)} for the translated
|
||||||
|
* result. You also need to implement {@link android.view.translation.ViewTranslationCallback} to
|
||||||
|
* handle the translated information show or hide in your {@link View}.
|
||||||
*/
|
*/
|
||||||
public final class UiTranslationManager {
|
public final class UiTranslationManager {
|
||||||
|
|
||||||
@ -248,14 +288,14 @@ public final class UiTranslationManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/178044703): Fix the View API link when it becomes public.
|
|
||||||
/**
|
/**
|
||||||
* Register for notifications of UI Translation state changes on the foreground activity. This
|
* Register for notifications of UI Translation state changes on the foreground activity. This
|
||||||
* is available to the owning application itself and also the current input method.
|
* is available to the owning application itself and also the current input method.
|
||||||
* <p>
|
* <p>
|
||||||
* The application whose UI is being translated can use this to customize the UI Translation
|
* The application whose UI is being translated can use this to customize the UI Translation
|
||||||
* behavior in ways that aren't made easy by methods like
|
* behavior in ways that aren't made easy by methods like
|
||||||
* View#onCreateTranslationRequest().
|
* {@link View#onCreateViewTranslationRequest(int[], Consumer)}.
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Input methods can use this to offer complementary features to UI Translation; for example,
|
* Input methods can use this to offer complementary features to UI Translation; for example,
|
||||||
* enabling outgoing message translation when the system is translating incoming messages in a
|
* enabling outgoing message translation when the system is translating incoming messages in a
|
||||||
|
@ -19,9 +19,17 @@ package android.view.translation;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.UiThread;
|
import android.annotation.UiThread;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.contentcapture.ContentCaptureSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for handling the translated information show or hide in the {@link View}.
|
* <p> Callback for handling the translated information show or hide in the {@link View}.
|
||||||
|
*
|
||||||
|
* <p> When the platform intelligence starts translation of an app's ui, the system will call
|
||||||
|
* {@link View#dispatchCreateViewTranslationRequest} to collect the {@link ViewTranslationRequest}s
|
||||||
|
* for translation purpose by traversing the hierarchy then send to translation service. After
|
||||||
|
* receiving the {@link ViewTranslationResponse}, the system will call
|
||||||
|
* {@link ViewTranslationCallback#onShowTranslation(View)} to show the translated information for
|
||||||
|
* the {@link View}.
|
||||||
*/
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public interface ViewTranslationCallback {
|
public interface ViewTranslationCallback {
|
||||||
@ -33,13 +41,24 @@ public interface ViewTranslationCallback {
|
|||||||
* method will not be called before {@link View#onViewTranslationResponse} or
|
* method will not be called before {@link View#onViewTranslationResponse} or
|
||||||
* {@link View#onVirtualViewTranslationResponses}.
|
* {@link View#onVirtualViewTranslationResponses}.
|
||||||
*
|
*
|
||||||
|
* <p> NOTE: It is possible the user changes text that causes a new
|
||||||
|
* {@link ViewTranslationResponse} returns to show the new translation. If you cache the
|
||||||
|
* {@link ViewTranslationResponse} here, you should remember to keep the cached value up
|
||||||
|
* to date.
|
||||||
|
*
|
||||||
|
* <p> NOTE: For TextView implementation, {@link ContentCaptureSession#notifyViewTextChanged}
|
||||||
|
* shouldn't be called with the translated text, simply calling setText() here will trigger the
|
||||||
|
* method. You should either override {@code View#onProvideContentCaptureStructure()} to report
|
||||||
|
* the original text instead of the translated text or use a different approach to display the
|
||||||
|
* translated text.
|
||||||
|
*
|
||||||
* See {@link View#onViewTranslationResponse} for how to get the translated information.
|
* See {@link View#onViewTranslationResponse} for how to get the translated information.
|
||||||
*
|
*
|
||||||
* @return {@code true} if the View handles showing the translation.
|
* @return {@code true} if the View handles showing the translation.
|
||||||
*/
|
*/
|
||||||
boolean onShowTranslation(@NonNull View view);
|
boolean onShowTranslation(@NonNull View view);
|
||||||
/**
|
/**
|
||||||
* Called when the user wants to show the original text instead of the translated text. This
|
* Called when user wants to view the original content instead of the translated content. This
|
||||||
* method will not be called before {@link View#onViewTranslationResponse} or
|
* method will not be called before {@link View#onViewTranslationResponse} or
|
||||||
* {@link View#onViewTranslationResponse}.
|
* {@link View#onViewTranslationResponse}.
|
||||||
*
|
*
|
||||||
@ -47,7 +66,8 @@ public interface ViewTranslationCallback {
|
|||||||
*/
|
*/
|
||||||
boolean onHideTranslation(@NonNull View view);
|
boolean onHideTranslation(@NonNull View view);
|
||||||
/**
|
/**
|
||||||
* Called when the user finish the Ui translation and no longer to show the translated text.
|
* Called when the translation state is no longer needed. It should restore the original content
|
||||||
|
* and clear all saved states.
|
||||||
*
|
*
|
||||||
* @return {@code true} if the View handles clearing the translation.
|
* @return {@code true} if the View handles clearing the translation.
|
||||||
*/
|
*/
|
||||||
|
@ -739,6 +739,16 @@ public class RemoteViews implements Parcelable, Filter {
|
|||||||
return mContextForResources.getPackageName();
|
return mContextForResources.getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserHandle getUser() {
|
||||||
|
return mContextForResources.getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getUserId() {
|
||||||
|
return mContextForResources.getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRestricted() {
|
public boolean isRestricted() {
|
||||||
// Override isRestricted and direct to resource's implementation. The isRestricted is
|
// Override isRestricted and direct to resource's implementation. The isRestricted is
|
||||||
|
@ -64,13 +64,24 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onShowTranslation(@NonNull View view) {
|
public boolean onShowTranslation(@NonNull View view) {
|
||||||
|
if (mIsShowingTranslation) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, view + " is already showing translated text.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ViewTranslationResponse response = view.getViewTranslationResponse();
|
ViewTranslationResponse response = view.getViewTranslationResponse();
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
Log.e(TAG, "onShowTranslation() shouldn't be called before "
|
Log.e(TAG, "onShowTranslation() shouldn't be called before "
|
||||||
+ "onViewTranslationResponse().");
|
+ "onViewTranslationResponse().");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mTranslationTransformation == null) {
|
// It is possible user changes text and new translation response returns, system should
|
||||||
|
// update the translation response to keep the result up to date.
|
||||||
|
// Because TextView.setTransformationMethod() will skip the same TransformationMethod
|
||||||
|
// instance, we should create a new one to let new translation can work.
|
||||||
|
if (mTranslationTransformation == null
|
||||||
|
|| !response.equals(mTranslationTransformation.getViewTranslationResponse())) {
|
||||||
TransformationMethod originalTranslationMethod =
|
TransformationMethod originalTranslationMethod =
|
||||||
((TextView) view).getTransformationMethod();
|
((TextView) view).getTransformationMethod();
|
||||||
mTranslationTransformation = new TranslationTransformationMethod(response,
|
mTranslationTransformation = new TranslationTransformationMethod(response,
|
||||||
@ -147,7 +158,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isShowingTranslation() {
|
public boolean isShowingTranslation() {
|
||||||
return mIsShowingTranslation;
|
return mIsShowingTranslation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,4 +88,9 @@ oneway interface ITaskOrganizer {
|
|||||||
* user has pressed back on the root activity of a task controlled by the task organizer.
|
* user has pressed back on the root activity of a task controlled by the task organizer.
|
||||||
*/
|
*/
|
||||||
void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
|
void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the IME has drawn on the organized task.
|
||||||
|
*/
|
||||||
|
void onImeDrawnOnTask(int taskId);
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,10 @@ public class TaskOrganizer extends WindowOrganizer {
|
|||||||
@BinderThread
|
@BinderThread
|
||||||
public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
|
public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
@BinderThread
|
||||||
|
public void onImeDrawnOnTask(int taskId) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a persistent root task in WM for a particular windowing-mode.
|
* Creates a persistent root task in WM for a particular windowing-mode.
|
||||||
* @param displayId The display to create the root task on.
|
* @param displayId The display to create the root task on.
|
||||||
@ -287,6 +291,11 @@ public class TaskOrganizer extends WindowOrganizer {
|
|||||||
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
|
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
|
||||||
mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info));
|
mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onImeDrawnOnTask(int taskId) {
|
||||||
|
mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private ITaskOrganizerController getController() {
|
private ITaskOrganizerController getController() {
|
||||||
|
@ -26,7 +26,6 @@ import android.content.Context;
|
|||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@ -67,7 +66,7 @@ public class WindowContext extends ContextWrapper {
|
|||||||
mType = type;
|
mType = type;
|
||||||
mOptions = options;
|
mOptions = options;
|
||||||
mWindowManager = createWindowContextWindowManager(this);
|
mWindowManager = createWindowContextWindowManager(this);
|
||||||
IBinder token = getWindowContextToken();
|
WindowTokenClient token = (WindowTokenClient) getWindowContextToken();
|
||||||
mController = new WindowContextController(token);
|
mController = new WindowContextController(token);
|
||||||
|
|
||||||
Reference.reachabilityFence(this);
|
Reference.reachabilityFence(this);
|
||||||
|
@ -19,6 +19,7 @@ package android.window;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@ -46,7 +47,7 @@ public class WindowContextController {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public boolean mAttachedToDisplayArea;
|
public boolean mAttachedToDisplayArea;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final IBinder mToken;
|
private final WindowTokenClient mToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window Context Controller constructor
|
* Window Context Controller constructor
|
||||||
@ -54,14 +55,13 @@ public class WindowContextController {
|
|||||||
* @param token The token used to attach to a window manager node. It is usually from
|
* @param token The token used to attach to a window manager node. It is usually from
|
||||||
* {@link Context#getWindowContextToken()}.
|
* {@link Context#getWindowContextToken()}.
|
||||||
*/
|
*/
|
||||||
public WindowContextController(@NonNull IBinder token) {
|
public WindowContextController(@NonNull WindowTokenClient token) {
|
||||||
mToken = token;
|
this(token, WindowManagerGlobal.getWindowManagerService());
|
||||||
mWms = WindowManagerGlobal.getWindowManagerService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used for test only. DO NOT USE it in production code. */
|
/** Used for test only. DO NOT USE it in production code. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) {
|
public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
|
||||||
mToken = token;
|
mToken = token;
|
||||||
mWms = mockWms;
|
mWms = mockWms;
|
||||||
}
|
}
|
||||||
@ -81,8 +81,14 @@ public class WindowContextController {
|
|||||||
+ "a DisplayArea once.");
|
+ "a DisplayArea once.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId,
|
final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
|
||||||
options);
|
displayId, options);
|
||||||
|
if (configuration != null) {
|
||||||
|
mAttachedToDisplayArea = true;
|
||||||
|
// Send the DisplayArea's configuration to WindowContext directly instead of
|
||||||
|
// waiting for dispatching from WMS.
|
||||||
|
mToken.onConfigurationChanged(configuration, displayId);
|
||||||
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ import android.content.res.Configuration;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +35,7 @@ import java.lang.ref.WeakReference;
|
|||||||
* {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}.
|
* {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}.
|
||||||
*
|
*
|
||||||
* @see WindowContext
|
* @see WindowContext
|
||||||
* @see android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, Bundle)
|
* @see android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, Bundle)
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@ -50,8 +52,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
|||||||
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
|
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
|
||||||
* can only attach one {@link Context}.
|
* can only attach one {@link Context}.
|
||||||
* <p>This method must be called before invoking
|
* <p>This method must be called before invoking
|
||||||
* {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int,
|
* {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
|
||||||
* Bundle, boolean)}.<p/>
|
* Bundle)}.<p/>
|
||||||
*
|
*
|
||||||
* @param context context to be attached
|
* @param context context to be attached
|
||||||
* @throws IllegalStateException if attached context has already existed.
|
* @throws IllegalStateException if attached context has already existed.
|
||||||
@ -63,6 +65,13 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
|||||||
mContextRef = new WeakReference<>(context);
|
mContextRef = new WeakReference<>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when {@link Configuration} updates from the server side receive.
|
||||||
|
*
|
||||||
|
* @param newConfig the updated {@link Configuration}
|
||||||
|
* @param newDisplayId the updated {@link android.view.Display} ID
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
|
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
|
||||||
final Context context = mContextRef.get();
|
final Context context = mContextRef.get();
|
||||||
|
@ -72,17 +72,19 @@ public class SuspendedAppActivity extends AlertActivity
|
|||||||
private Resources mSuspendingAppResources;
|
private Resources mSuspendingAppResources;
|
||||||
private SuspendDialogInfo mSuppliedDialogInfo;
|
private SuspendDialogInfo mSuppliedDialogInfo;
|
||||||
private Bundle mOptions;
|
private Bundle mOptions;
|
||||||
private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver mSuspendModifiedReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) {
|
if (Intent.ACTION_PACKAGES_SUSPENSION_CHANGED.equals(intent.getAction())) {
|
||||||
final String[] unsuspended = intent.getStringArrayExtra(
|
// Suspension conditions were modified, dismiss any related visible dialogs.
|
||||||
|
final String[] modified = intent.getStringArrayExtra(
|
||||||
Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||||
if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) {
|
if (ArrayUtils.contains(modified, mSuspendedPackage)) {
|
||||||
if (!isFinishing()) {
|
if (!isFinishing()) {
|
||||||
Slog.w(TAG, "Package " + mSuspendedPackage
|
Slog.w(TAG, "Package " + mSuspendedPackage + " has modified"
|
||||||
+ " got unsuspended while the dialog was visible. Finishing.");
|
+ " suspension conditions while dialog was visible. Finishing.");
|
||||||
SuspendedAppActivity.this.finish();
|
SuspendedAppActivity.this.finish();
|
||||||
|
// TODO (b/198201994): reload the suspend dialog to show most relevant info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,15 +247,16 @@ public class SuspendedAppActivity extends AlertActivity
|
|||||||
|
|
||||||
setupAlert();
|
setupAlert();
|
||||||
|
|
||||||
final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED);
|
final IntentFilter suspendModifiedFilter =
|
||||||
registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null,
|
new IntentFilter(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED);
|
||||||
null);
|
registerReceiverAsUser(mSuspendModifiedReceiver, UserHandle.of(mUserId),
|
||||||
|
suspendModifiedFilter, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
unregisterReceiver(mUnsuspendReceiver);
|
unregisterReceiver(mSuspendModifiedReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {
|
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {
|
||||||
|
@ -165,7 +165,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
|
|||||||
|
|
||||||
// Now fetch app icon and raster with no badging even in work profile
|
// Now fetch app icon and raster with no badging even in work profile
|
||||||
Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
|
Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
|
||||||
.getIconBitmap(android.os.Process.myUserHandle());
|
.getIconBitmap(mContext.getUser());
|
||||||
|
|
||||||
// Raster target drawable with appIcon as a badge
|
// Raster target drawable with appIcon as a badge
|
||||||
SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);
|
SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);
|
||||||
|
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.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that allows the app to get the frame metrics from HardwareRendererObserver.
|
* A class that allows the app to get the frame metrics from HardwareRendererObserver.
|
||||||
@ -103,6 +104,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
|||||||
private boolean mCancelled = false;
|
private boolean mCancelled = false;
|
||||||
private FrameTrackerListener mListener;
|
private FrameTrackerListener mListener;
|
||||||
private boolean mTracingStarted = false;
|
private boolean mTracingStarted = false;
|
||||||
|
private Runnable mWaitForFinishTimedOut;
|
||||||
|
|
||||||
private static class JankInfo {
|
private static class JankInfo {
|
||||||
long frameVsyncId;
|
long frameVsyncId;
|
||||||
@ -263,10 +265,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
|||||||
if (mListener != null) {
|
if (mListener != null) {
|
||||||
mListener.onCujEvents(mSession, ACTION_SESSION_END);
|
mListener.onCujEvents(mSession, ACTION_SESSION_END);
|
||||||
}
|
}
|
||||||
|
// We don't remove observer here,
|
||||||
|
// will remove it when all the frame metrics in this duration are called back.
|
||||||
|
// See onFrameMetricsAvailable for the logic of removing the observer.
|
||||||
|
// Waiting at most 10 seconds for all callbacks to finish.
|
||||||
|
mWaitForFinishTimedOut = () -> {
|
||||||
|
Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
|
||||||
|
finish(mJankInfos.size() - 1);
|
||||||
|
};
|
||||||
|
mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
|
||||||
}
|
}
|
||||||
// We don't remove observer here,
|
|
||||||
// will remove it when all the frame metrics in this duration are called back.
|
|
||||||
// See onFrameMetricsAvailable for the logic of removing the observer.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,7 +404,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void finish(int indexOnOrAfterEnd) {
|
private void finish(int indexOnOrAfterEnd) {
|
||||||
|
mHandler.removeCallbacks(mWaitForFinishTimedOut);
|
||||||
|
mWaitForFinishTimedOut = null;
|
||||||
mMetricsFinalized = true;
|
mMetricsFinalized = true;
|
||||||
|
|
||||||
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
|
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
|
||||||
@ -481,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
|
Log.i(TAG, "finish: CUJ=" + mSession.getName()
|
||||||
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
|
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
|
||||||
+ " totalFrames=" + totalFramesCount
|
+ " totalFrames=" + totalFramesCount
|
||||||
+ " missedAppFrames=" + missedAppFramesCount
|
+ " missedAppFrames=" + missedAppFramesCount
|
||||||
|
@ -103,7 +103,7 @@ public class InteractionJankMonitor {
|
|||||||
private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
|
private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
|
||||||
|
|
||||||
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
|
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
|
||||||
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
|
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L);
|
||||||
private static final String SETTINGS_ENABLED_KEY = "enabled";
|
private static final String SETTINGS_ENABLED_KEY = "enabled";
|
||||||
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
|
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
|
||||||
private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =
|
private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =
|
||||||
|
@ -707,6 +707,10 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
* Mapping isolated uids to the actual owning app uid.
|
* Mapping isolated uids to the actual owning app uid.
|
||||||
*/
|
*/
|
||||||
final SparseIntArray mIsolatedUids = new SparseIntArray();
|
final SparseIntArray mIsolatedUids = new SparseIntArray();
|
||||||
|
/**
|
||||||
|
* Internal reference count of isolated uids.
|
||||||
|
*/
|
||||||
|
final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The statistics we have collected organized by uids.
|
* The statistics we have collected organized by uids.
|
||||||
@ -3897,6 +3901,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
public void addIsolatedUidLocked(int isolatedUid, int appUid,
|
public void addIsolatedUidLocked(int isolatedUid, int appUid,
|
||||||
long elapsedRealtimeMs, long uptimeMs) {
|
long elapsedRealtimeMs, long uptimeMs) {
|
||||||
mIsolatedUids.put(isolatedUid, appUid);
|
mIsolatedUids.put(isolatedUid, appUid);
|
||||||
|
mIsolatedUidRefCounts.put(isolatedUid, 1);
|
||||||
final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
|
final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
|
||||||
u.addIsolatedUid(isolatedUid);
|
u.addIsolatedUid(isolatedUid);
|
||||||
}
|
}
|
||||||
@ -3915,19 +3920,51 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should only be called after the cpu times have been read.
|
* Isolated uid should only be removed after all wakelocks associated with the uid are stopped
|
||||||
|
* and the cpu time-in-state has been read one last time for the uid.
|
||||||
|
*
|
||||||
* @see #scheduleRemoveIsolatedUidLocked(int, int)
|
* @see #scheduleRemoveIsolatedUidLocked(int, int)
|
||||||
|
*
|
||||||
|
* @return true if the isolated uid is actually removed.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
|
public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs,
|
||||||
|
long uptimeMs) {
|
||||||
|
final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1;
|
||||||
|
if (refCount > 0) {
|
||||||
|
// Isolated uid is still being tracked
|
||||||
|
mIsolatedUidRefCounts.put(isolatedUid, refCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
|
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
final int ownerUid = mIsolatedUids.valueAt(idx);
|
final int ownerUid = mIsolatedUids.valueAt(idx);
|
||||||
final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
|
final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
|
||||||
u.removeIsolatedUid(isolatedUid);
|
u.removeIsolatedUid(isolatedUid);
|
||||||
mIsolatedUids.removeAt(idx);
|
mIsolatedUids.removeAt(idx);
|
||||||
|
mIsolatedUidRefCounts.delete(isolatedUid);
|
||||||
|
} else {
|
||||||
|
Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")");
|
||||||
}
|
}
|
||||||
mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
|
mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the ref count for an isolated uid.
|
||||||
|
* call #maybeRemoveIsolatedUidLocked to decrement.
|
||||||
|
*/
|
||||||
|
public void incrementIsolatedUidRefCount(int uid) {
|
||||||
|
final int refCount = mIsolatedUidRefCounts.get(uid, 0);
|
||||||
|
if (refCount <= 0) {
|
||||||
|
// Uid is not mapped or referenced
|
||||||
|
Slog.w(TAG,
|
||||||
|
"Attempted to increment ref counted of untracked isolated uid (" + uid + ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsolatedUidRefCounts.put(uid, refCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int mapUid(int uid) {
|
public int mapUid(int uid) {
|
||||||
@ -4287,7 +4324,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
|
|
||||||
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
|
public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
|
||||||
int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
|
int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
|
||||||
uid = mapUid(uid);
|
final int mappedUid = mapUid(uid);
|
||||||
if (type == WAKE_TYPE_PARTIAL) {
|
if (type == WAKE_TYPE_PARTIAL) {
|
||||||
// Only care about partial wake locks, since full wake locks
|
// Only care about partial wake locks, since full wake locks
|
||||||
// will be canceled when the user puts the screen to sleep.
|
// will be canceled when the user puts the screen to sleep.
|
||||||
@ -4297,9 +4334,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
}
|
}
|
||||||
if (mRecordAllHistory) {
|
if (mRecordAllHistory) {
|
||||||
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
|
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
|
||||||
uid, 0)) {
|
mappedUid, 0)) {
|
||||||
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
|
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
|
||||||
HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
|
HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mWakeLockNesting == 0) {
|
if (mWakeLockNesting == 0) {
|
||||||
@ -4308,7 +4345,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
+ Integer.toHexString(mHistoryCur.states));
|
+ Integer.toHexString(mHistoryCur.states));
|
||||||
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
|
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
|
||||||
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
|
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
|
||||||
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
|
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
|
||||||
mWakeLockImportant = !unimportantForLogging;
|
mWakeLockImportant = !unimportantForLogging;
|
||||||
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
||||||
} else if (!mWakeLockImportant && !unimportantForLogging
|
} else if (!mWakeLockImportant && !unimportantForLogging
|
||||||
@ -4318,14 +4355,19 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
mHistoryLastWritten.wakelockTag = null;
|
mHistoryLastWritten.wakelockTag = null;
|
||||||
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
|
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
|
||||||
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
|
mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
|
||||||
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
|
mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid;
|
||||||
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
||||||
}
|
}
|
||||||
mWakeLockImportant = true;
|
mWakeLockImportant = true;
|
||||||
}
|
}
|
||||||
mWakeLockNesting++;
|
mWakeLockNesting++;
|
||||||
}
|
}
|
||||||
if (uid >= 0) {
|
if (mappedUid >= 0) {
|
||||||
|
if (mappedUid != uid) {
|
||||||
|
// Prevent the isolated uid mapping from being removed while the wakelock is
|
||||||
|
// being held.
|
||||||
|
incrementIsolatedUidRefCount(uid);
|
||||||
|
}
|
||||||
if (mOnBatteryScreenOffTimeBase.isRunning()) {
|
if (mOnBatteryScreenOffTimeBase.isRunning()) {
|
||||||
// We only update the cpu time when a wake lock is acquired if the screen is off.
|
// We only update the cpu time when a wake lock is acquired if the screen is off.
|
||||||
// If the screen is on, we don't distribute the power amongst partial wakelocks.
|
// If the screen is on, we don't distribute the power amongst partial wakelocks.
|
||||||
@ -4335,7 +4377,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
requestWakelockCpuUpdate();
|
requestWakelockCpuUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
|
getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
|
||||||
.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
|
.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
|
||||||
|
|
||||||
if (wc != null) {
|
if (wc != null) {
|
||||||
@ -4343,8 +4385,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
|
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
|
||||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
|
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
|
||||||
} else {
|
} else {
|
||||||
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
|
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
|
||||||
null, getPowerManagerWakeLockLevel(type), name,
|
mappedUid, null, getPowerManagerWakeLockLevel(type), name,
|
||||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
|
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4358,7 +4400,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
|
|
||||||
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
|
public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
|
||||||
int type, long elapsedRealtimeMs, long uptimeMs) {
|
int type, long elapsedRealtimeMs, long uptimeMs) {
|
||||||
uid = mapUid(uid);
|
final int mappedUid = mapUid(uid);
|
||||||
if (type == WAKE_TYPE_PARTIAL) {
|
if (type == WAKE_TYPE_PARTIAL) {
|
||||||
mWakeLockNesting--;
|
mWakeLockNesting--;
|
||||||
if (mRecordAllHistory) {
|
if (mRecordAllHistory) {
|
||||||
@ -4366,9 +4408,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
historyName = name;
|
historyName = name;
|
||||||
}
|
}
|
||||||
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
|
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
|
||||||
uid, 0)) {
|
mappedUid, 0)) {
|
||||||
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
|
addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
|
||||||
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
|
HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mWakeLockNesting == 0) {
|
if (mWakeLockNesting == 0) {
|
||||||
@ -4380,7 +4422,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (uid >= 0) {
|
if (mappedUid >= 0) {
|
||||||
if (mOnBatteryScreenOffTimeBase.isRunning()) {
|
if (mOnBatteryScreenOffTimeBase.isRunning()) {
|
||||||
if (DEBUG_ENERGY_CPU) {
|
if (DEBUG_ENERGY_CPU) {
|
||||||
Slog.d(TAG, "Updating cpu time because of -wake_lock");
|
Slog.d(TAG, "Updating cpu time because of -wake_lock");
|
||||||
@ -4388,17 +4430,22 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
requestWakelockCpuUpdate();
|
requestWakelockCpuUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
|
getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs)
|
||||||
.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
|
.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
|
||||||
if (wc != null) {
|
if (wc != null) {
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
|
FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
|
||||||
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
|
wc.getTags(), getPowerManagerWakeLockLevel(type), name,
|
||||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
|
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
|
||||||
} else {
|
} else {
|
||||||
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid,
|
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
|
||||||
null, getPowerManagerWakeLockLevel(type), name,
|
mappedUid, null, getPowerManagerWakeLockLevel(type), name,
|
||||||
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
|
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mappedUid != uid) {
|
||||||
|
// Decrement the ref count for the isolated uid and delete the mapping if uneeded.
|
||||||
|
maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8571,7 +8618,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
* inactive so can be dropped.
|
* inactive so can be dropped.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||||
public boolean reset(long uptimeUs, long realtimeUs) {
|
public boolean reset(long uptimeUs, long realtimeUs, int resetReason) {
|
||||||
boolean active = false;
|
boolean active = false;
|
||||||
|
|
||||||
mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs);
|
mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs);
|
||||||
@ -8641,7 +8688,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs);
|
resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs);
|
||||||
resetIfNotNull(mModemControllerActivity, false, realtimeUs);
|
resetIfNotNull(mModemControllerActivity, false, realtimeUs);
|
||||||
|
|
||||||
MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats);
|
if (resetReason == RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE) {
|
||||||
|
mUidMeasuredEnergyStats = null;
|
||||||
|
} else {
|
||||||
|
MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats);
|
||||||
|
}
|
||||||
|
|
||||||
resetIfNotNull(mUserCpuTime, false, realtimeUs);
|
resetIfNotNull(mUserCpuTime, false, realtimeUs);
|
||||||
resetIfNotNull(mSystemCpuTime, false, realtimeUs);
|
resetIfNotNull(mSystemCpuTime, false, realtimeUs);
|
||||||
@ -11324,7 +11375,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
mNumConnectivityChange = 0;
|
mNumConnectivityChange = 0;
|
||||||
|
|
||||||
for (int i=0; i<mUidStats.size(); i++) {
|
for (int i=0; i<mUidStats.size(); i++) {
|
||||||
if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs)) {
|
if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs, resetReason)) {
|
||||||
mUidStats.valueAt(i).detachFromTimeBase();
|
mUidStats.valueAt(i).detachFromTimeBase();
|
||||||
mUidStats.remove(mUidStats.keyAt(i));
|
mUidStats.remove(mUidStats.keyAt(i));
|
||||||
i--;
|
i--;
|
||||||
@ -16761,6 +16812,15 @@ public class BatteryStatsImpl extends BatteryStats {
|
|||||||
pw.print("UIDs removed since the later of device start or stats reset: ");
|
pw.print("UIDs removed since the later of device start or stats reset: ");
|
||||||
pw.println(mNumUidsRemoved);
|
pw.println(mNumUidsRemoved);
|
||||||
|
|
||||||
|
pw.println("Currently mapped isolated uids:");
|
||||||
|
final int numIsolatedUids = mIsolatedUids.size();
|
||||||
|
for (int i = 0; i < numIsolatedUids; i++) {
|
||||||
|
final int isolatedUid = mIsolatedUids.keyAt(i);
|
||||||
|
final int ownerUid = mIsolatedUids.valueAt(i);
|
||||||
|
final int refCount = mIsolatedUidRefCounts.get(isolatedUid);
|
||||||
|
pw.println(" " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")");
|
||||||
|
}
|
||||||
|
|
||||||
pw.println();
|
pw.println();
|
||||||
dumpConstantsLocked(pw);
|
dumpConstantsLocked(pw);
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import android.util.SparseArray;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -234,8 +235,9 @@ public class BatteryUsageStatsProvider {
|
|||||||
final boolean includePowerModels = (query.getFlags()
|
final boolean includePowerModels = (query.getFlags()
|
||||||
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
|
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
|
||||||
|
|
||||||
|
final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames();
|
||||||
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
|
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
|
||||||
mStats.getCustomEnergyConsumerNames(), includePowerModels);
|
customEnergyConsumerNames, includePowerModels);
|
||||||
if (mBatteryUsageStatsStore == null) {
|
if (mBatteryUsageStatsStore == null) {
|
||||||
Log.e(TAG, "BatteryUsageStatsStore is unavailable");
|
Log.e(TAG, "BatteryUsageStatsStore is unavailable");
|
||||||
return builder.build();
|
return builder.build();
|
||||||
@ -247,7 +249,14 @@ public class BatteryUsageStatsProvider {
|
|||||||
final BatteryUsageStats snapshot =
|
final BatteryUsageStats snapshot =
|
||||||
mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
|
mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
|
||||||
if (snapshot != null) {
|
if (snapshot != null) {
|
||||||
builder.add(snapshot);
|
if (Arrays.equals(snapshot.getCustomPowerComponentNames(),
|
||||||
|
customEnergyConsumerNames)) {
|
||||||
|
builder.add(snapshot);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different "
|
||||||
|
+ "custom power components: "
|
||||||
|
+ Arrays.toString(snapshot.getCustomPowerComponentNames()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,18 @@ import android.os.BatteryStats;
|
|||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
import android.os.BatteryUsageStatsQuery;
|
import android.os.BatteryUsageStatsQuery;
|
||||||
import android.os.UidBatteryConsumer;
|
import android.os.UidBatteryConsumer;
|
||||||
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type
|
* Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type
|
||||||
* {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
|
* {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
|
||||||
*/
|
*/
|
||||||
public class CustomMeasuredPowerCalculator extends PowerCalculator {
|
public class CustomMeasuredPowerCalculator extends PowerCalculator {
|
||||||
|
private static final String TAG = "CustomMeasuredPowerCalc";
|
||||||
|
|
||||||
public CustomMeasuredPowerCalculator(PowerProfile powerProfile) {
|
public CustomMeasuredPowerCalculator(PowerProfile powerProfile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,9 +81,9 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator {
|
|||||||
if (totalPowerMah == null) {
|
if (totalPowerMah == null) {
|
||||||
newTotalPowerMah = new double[customMeasuredPowerMah.length];
|
newTotalPowerMah = new double[customMeasuredPowerMah.length];
|
||||||
} else if (totalPowerMah.length != customMeasuredPowerMah.length) {
|
} else if (totalPowerMah.length != customMeasuredPowerMah.length) {
|
||||||
newTotalPowerMah = new double[customMeasuredPowerMah.length];
|
Slog.wtf(TAG, "Number of custom energy components is not the same for all apps: "
|
||||||
System.arraycopy(totalPowerMah, 0, newTotalPowerMah, 0,
|
+ totalPowerMah.length + ", " + customMeasuredPowerMah.length);
|
||||||
customMeasuredPowerMah.length);
|
newTotalPowerMah = Arrays.copyOf(totalPowerMah, customMeasuredPowerMah.length);
|
||||||
} else {
|
} else {
|
||||||
newTotalPowerMah = totalPowerMah;
|
newTotalPowerMah = totalPowerMah;
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,9 @@ public class WifiPowerCalculator extends PowerCalculator {
|
|||||||
+ "ms tx=" + txTime + "ms power=" + formatCharge(
|
+ "ms tx=" + txTime + "ms power=" + formatCharge(
|
||||||
powerDurationAndTraffic.powerMah));
|
powerDurationAndTraffic.powerMah));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
powerDurationAndTraffic.durationMs = 0;
|
||||||
|
powerDurationAndTraffic.powerMah = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
|
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
|
||||||
|
@ -124,7 +124,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
|||||||
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
|
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
try {
|
try {
|
||||||
sendCloseSystemWindows();
|
|
||||||
mContext.startActivity(intent);
|
mContext.startActivity(intent);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
startCallActivity();
|
startCallActivity();
|
||||||
@ -147,7 +146,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
|||||||
dispatcher.performedLongPress(event);
|
dispatcher.performedLongPress(event);
|
||||||
if (isUserSetupComplete()) {
|
if (isUserSetupComplete()) {
|
||||||
mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||||
sendCloseSystemWindows();
|
|
||||||
// Broadcast an intent that the Camera button was longpressed
|
// Broadcast an intent that the Camera button was longpressed
|
||||||
Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
|
Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
|
||||||
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||||
@ -178,7 +176,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
|||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
try {
|
try {
|
||||||
mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||||
sendCloseSystemWindows();
|
|
||||||
getSearchManager().stopSearch();
|
getSearchManager().stopSearch();
|
||||||
mContext.startActivity(intent);
|
mContext.startActivity(intent);
|
||||||
// Only clear this if we successfully start the
|
// Only clear this if we successfully start the
|
||||||
@ -272,7 +269,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
|||||||
|
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
void startCallActivity() {
|
void startCallActivity() {
|
||||||
sendCloseSystemWindows();
|
|
||||||
Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
|
Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
try {
|
try {
|
||||||
@ -319,10 +315,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
|
|||||||
return mMediaSessionManager;
|
return mMediaSessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendCloseSystemWindows() {
|
|
||||||
PhoneWindow.sendCloseSystemWindows(mContext, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleVolumeKeyEvent(KeyEvent keyEvent) {
|
private void handleVolumeKeyEvent(KeyEvent keyEvent) {
|
||||||
getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent,
|
getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent,
|
||||||
AudioManager.USE_DEFAULT_STREAM_TYPE);
|
AudioManager.USE_DEFAULT_STREAM_TYPE);
|
||||||
|
@ -148,7 +148,7 @@ oneway interface IStatusBar
|
|||||||
*/
|
*/
|
||||||
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
|
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
|
||||||
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
|
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
|
||||||
String opPackageName, long operationId, int multiSensorConfig);
|
long operationId, String opPackageName, long requestId, int multiSensorConfig);
|
||||||
/**
|
/**
|
||||||
* Used to notify the authentication dialog that a biometric has been authenticated.
|
* Used to notify the authentication dialog that a biometric has been authenticated.
|
||||||
*/
|
*/
|
||||||
|
@ -110,7 +110,8 @@ interface IStatusBarService
|
|||||||
// Used to show the authentication dialog (Biometrics, Device Credential)
|
// Used to show the authentication dialog (Biometrics, Device Credential)
|
||||||
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
|
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
|
||||||
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
|
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
|
||||||
int userId, String opPackageName, long operationId, int multiSensorConfig);
|
int userId, long operationId, String opPackageName, long requestId,
|
||||||
|
int multiSensorConfig);
|
||||||
|
|
||||||
// Used to notify the authentication dialog that a biometric has been authenticated
|
// Used to notify the authentication dialog that a biometric has been authenticated
|
||||||
void onBiometricAuthenticated();
|
void onBiometricAuthenticated();
|
||||||
|
@ -291,10 +291,10 @@ public class ContrastColorUtil {
|
|||||||
* Finds a suitable color such that there's enough contrast.
|
* Finds a suitable color such that there's enough contrast.
|
||||||
*
|
*
|
||||||
* @param color the color to start searching from.
|
* @param color the color to start searching from.
|
||||||
* @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
|
* @param other the color to ensure contrast against. Assumed to be lighter than {@code color}
|
||||||
* @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
|
* @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
|
||||||
* @param minRatio the minimum contrast ratio required.
|
* @param minRatio the minimum contrast ratio required.
|
||||||
* @return a color with the same hue as {@param color}, potentially darkened to meet the
|
* @return a color with the same hue as {@code color}, potentially darkened to meet the
|
||||||
* contrast ratio.
|
* contrast ratio.
|
||||||
*/
|
*/
|
||||||
public static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
|
public static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
|
||||||
@ -331,7 +331,7 @@ public class ContrastColorUtil {
|
|||||||
* @param color the color to start searching from.
|
* @param color the color to start searching from.
|
||||||
* @param backgroundColor the color to ensure contrast against.
|
* @param backgroundColor the color to ensure contrast against.
|
||||||
* @param minRatio the minimum contrast ratio required.
|
* @param minRatio the minimum contrast ratio required.
|
||||||
* @return the same color as {@param color} with potentially modified alpha to meet contrast
|
* @return the same color as {@code color} with potentially modified alpha to meet contrast
|
||||||
*/
|
*/
|
||||||
public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
|
public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
|
||||||
int fg = color;
|
int fg = color;
|
||||||
@ -361,10 +361,10 @@ public class ContrastColorUtil {
|
|||||||
* Finds a suitable color such that there's enough contrast.
|
* Finds a suitable color such that there's enough contrast.
|
||||||
*
|
*
|
||||||
* @param color the color to start searching from.
|
* @param color the color to start searching from.
|
||||||
* @param other the color to ensure contrast against. Assumed to be darker than {@param color}
|
* @param other the color to ensure contrast against. Assumed to be darker than {@code color}
|
||||||
* @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
|
* @param findFg if true, we assume {@code color} is a foreground, otherwise a background.
|
||||||
* @param minRatio the minimum contrast ratio required.
|
* @param minRatio the minimum contrast ratio required.
|
||||||
* @return a color with the same hue as {@param color}, potentially darkened to meet the
|
* @return a color with the same hue as {@code color}, potentially lightened to meet the
|
||||||
* contrast ratio.
|
* contrast ratio.
|
||||||
*/
|
*/
|
||||||
public static int findContrastColorAgainstDark(int color, int other, boolean findFg,
|
public static int findContrastColorAgainstDark(int color, int other, boolean findFg,
|
||||||
@ -393,7 +393,8 @@ public class ContrastColorUtil {
|
|||||||
low = l;
|
low = l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return findFg ? fg : bg;
|
hsl[2] = high;
|
||||||
|
return ColorUtilsFromCompat.HSLToColor(hsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int ensureTextContrastOnBlack(int color) {
|
public static int ensureTextContrastOnBlack(int color) {
|
||||||
@ -452,7 +453,7 @@ public class ContrastColorUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
|
* Resolves {@code color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
|
||||||
*/
|
*/
|
||||||
public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
|
public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
|
||||||
if (color == Notification.COLOR_DEFAULT) {
|
if (color == Notification.COLOR_DEFAULT) {
|
||||||
|
@ -4,4 +4,3 @@ per-file *Notification* = file:/services/core/java/com/android/server/notificati
|
|||||||
per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
|
per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
|
||||||
per-file Protocol* = etancohen@google.com, lorenzo@google.com
|
per-file Protocol* = etancohen@google.com, lorenzo@google.com
|
||||||
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
|
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
|
||||||
per-file DataClass* = eugenesusla@google.com
|
|
@ -17,6 +17,7 @@
|
|||||||
package com.android.internal.widget;
|
package com.android.internal.widget;
|
||||||
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
||||||
@ -1271,6 +1272,14 @@ public class LockPatternUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user is not allowed to set any credentials via PASSWORD_QUALITY_MANAGED.
|
||||||
|
*/
|
||||||
|
public boolean isCredentialsDisabledForUser(int userId) {
|
||||||
|
return getDevicePolicyManager().getPasswordQuality(/* admin= */ null, userId)
|
||||||
|
== PASSWORD_QUALITY_MANAGED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see StrongAuthTracker#isTrustAllowedForUser
|
* @see StrongAuthTracker#isTrustAllowedForUser
|
||||||
*/
|
*/
|
||||||
|
@ -53,6 +53,8 @@ public class NotificationActionListLayout extends LinearLayout {
|
|||||||
private int mEmphasizedHeight;
|
private int mEmphasizedHeight;
|
||||||
private int mRegularHeight;
|
private int mRegularHeight;
|
||||||
@DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
|
@DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
|
||||||
|
int mNumNotGoneChildren;
|
||||||
|
int mNumPriorityChildren;
|
||||||
|
|
||||||
public NotificationActionListLayout(Context context, AttributeSet attrs) {
|
public NotificationActionListLayout(Context context, AttributeSet attrs) {
|
||||||
this(context, attrs, 0);
|
this(context, attrs, 0);
|
||||||
@ -76,15 +78,14 @@ public class NotificationActionListLayout extends LinearLayout {
|
|||||||
&& ((EmphasizedNotificationButton) actionView).isPriority();
|
&& ((EmphasizedNotificationButton) actionView).isPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void countAndRebuildMeasureOrder() {
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
final int numChildren = getChildCount();
|
||||||
final int N = getChildCount();
|
|
||||||
int textViews = 0;
|
int textViews = 0;
|
||||||
int otherViews = 0;
|
int otherViews = 0;
|
||||||
int notGoneChildren = 0;
|
mNumNotGoneChildren = 0;
|
||||||
int priorityChildren = 0;
|
mNumPriorityChildren = 0;
|
||||||
|
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < numChildren; i++) {
|
||||||
View c = getChildAt(i);
|
View c = getChildAt(i);
|
||||||
if (c instanceof TextView) {
|
if (c instanceof TextView) {
|
||||||
textViews++;
|
textViews++;
|
||||||
@ -92,9 +93,9 @@ public class NotificationActionListLayout extends LinearLayout {
|
|||||||
otherViews++;
|
otherViews++;
|
||||||
}
|
}
|
||||||
if (c.getVisibility() != GONE) {
|
if (c.getVisibility() != GONE) {
|
||||||
notGoneChildren++;
|
mNumNotGoneChildren++;
|
||||||
if (isPriority(c)) {
|
if (isPriority(c)) {
|
||||||
priorityChildren++;
|
mNumPriorityChildren++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,17 +120,20 @@ public class NotificationActionListLayout extends LinearLayout {
|
|||||||
if (needRebuild) {
|
if (needRebuild) {
|
||||||
rebuildMeasureOrder(textViews, otherViews);
|
rebuildMeasureOrder(textViews, otherViews);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int measureAndGetUsedWidth(int widthMeasureSpec, int heightMeasureSpec, int innerWidth,
|
||||||
|
boolean collapsePriorityActions) {
|
||||||
|
final int numChildren = getChildCount();
|
||||||
final boolean constrained =
|
final boolean constrained =
|
||||||
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
|
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
|
||||||
|
|
||||||
final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
|
|
||||||
final int otherSize = mMeasureOrderOther.size();
|
final int otherSize = mMeasureOrderOther.size();
|
||||||
int usedWidth = 0;
|
int usedWidth = 0;
|
||||||
|
|
||||||
|
int maxPriorityWidth = 0;
|
||||||
int measuredChildren = 0;
|
int measuredChildren = 0;
|
||||||
int measuredPriorityChildren = 0;
|
int measuredPriorityChildren = 0;
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < numChildren; i++) {
|
||||||
// Measure shortest children first. To avoid measuring twice, we approximate by looking
|
// Measure shortest children first. To avoid measuring twice, we approximate by looking
|
||||||
// at the text length.
|
// at the text length.
|
||||||
final boolean isPriority;
|
final boolean isPriority;
|
||||||
@ -154,12 +158,20 @@ public class NotificationActionListLayout extends LinearLayout {
|
|||||||
// measure in the order of (approx.) size, a large view can still take more than its
|
// measure in the order of (approx.) size, a large view can still take more than its
|
||||||
// share if the others are small.
|
// share if the others are small.
|
||||||
int availableWidth = innerWidth - usedWidth;
|
int availableWidth = innerWidth - usedWidth;
|
||||||
int unmeasuredChildren = notGoneChildren - measuredChildren;
|
int unmeasuredChildren = mNumNotGoneChildren - measuredChildren;
|
||||||
int maxWidthForChild = availableWidth / unmeasuredChildren;
|
int maxWidthForChild = availableWidth / unmeasuredChildren;
|
||||||
if (isPriority) {
|
if (isPriority && collapsePriorityActions) {
|
||||||
|
// Collapsing the actions to just the width required to show the icon.
|
||||||
|
if (maxPriorityWidth == 0) {
|
||||||
|
maxPriorityWidth = getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.notification_actions_collapsed_priority_width);
|
||||||
|
}
|
||||||
|
maxWidthForChild = maxPriorityWidth + lp.leftMargin + lp.rightMargin;
|
||||||
|
} else if (isPriority) {
|
||||||
// Priority children get a larger maximum share of the total space:
|
// Priority children get a larger maximum share of the total space:
|
||||||
// maximum priority share = (nPriority + 1) / (MAX + 1)
|
// maximum priority share = (nPriority + 1) / (MAX + 1)
|
||||||
int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren;
|
int unmeasuredPriorityChildren = mNumPriorityChildren
|
||||||
|
- measuredPriorityChildren;
|
||||||
int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
|
int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
|
||||||
int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
|
int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
|
||||||
/ (Notification.MAX_ACTION_BUTTONS + 1);
|
/ (Notification.MAX_ACTION_BUTTONS + 1);
|
||||||
@ -187,6 +199,19 @@ public class NotificationActionListLayout extends LinearLayout {
|
|||||||
} else {
|
} else {
|
||||||
mExtraStartPadding = 0;
|
mExtraStartPadding = 0;
|
||||||
}
|
}
|
||||||
|
return usedWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
countAndRebuildMeasureOrder();
|
||||||
|
final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
|
||||||
|
int usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth,
|
||||||
|
false /* collapsePriorityButtons */);
|
||||||
|
if (mNumPriorityChildren != 0 && usedWidth >= innerWidth) {
|
||||||
|
usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth,
|
||||||
|
true /* collapsePriorityButtons */);
|
||||||
|
}
|
||||||
|
|
||||||
mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding;
|
mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding;
|
||||||
setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
|
setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user