diff options
523 files changed, 14869 insertions, 3306 deletions
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp index b2b66c27f795..3534624a58a2 100644 --- a/cmds/bootanimation/Android.bp +++ b/cmds/bootanimation/Android.bp @@ -71,7 +71,7 @@ cc_library_shared { "libui", "libjnigraphics", "libEGL", - "libGLESv1_CM", + "libGLESv2", "libgui", ], } diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 3109c5c1e075..6c8cab7783b6 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -52,9 +52,8 @@ #include <gui/DisplayEventReceiver.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> #include <EGL/eglext.h> #include "BootAnimation.h" @@ -108,6 +107,93 @@ static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress"; static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays"; static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1; static constexpr size_t TEXT_POS_LEN_MAX = 16; +static const int DYNAMIC_COLOR_COUNT = 4; +static const char U_TEXTURE[] = "uTexture"; +static const char U_FADE[] = "uFade"; +static const char U_CROP_AREA[] = "uCropArea"; +static const char U_START_COLOR_PREFIX[] = "uStartColor"; +static const char U_END_COLOR_PREFIX[] = "uEndColor"; +static const char U_COLOR_PROGRESS[] = "uColorProgress"; +static const char A_UV[] = "aUv"; +static const char A_POSITION[] = "aPosition"; +static const char VERTEX_SHADER_SOURCE[] = R"( + precision mediump float; + attribute vec4 aPosition; + attribute highp vec2 aUv; + varying highp vec2 vUv; + void main() { + gl_Position = aPosition; + vUv = aUv; + })"; +static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"( + precision mediump float; + const float cWhiteMaskThreshold = 0.05; + uniform sampler2D uTexture; + uniform float uFade; + uniform float uColorProgress; + uniform vec4 uStartColor0; + uniform vec4 uStartColor1; + uniform vec4 uStartColor2; + uniform vec4 uStartColor3; + uniform vec4 uEndColor0; + uniform vec4 uEndColor1; + uniform vec4 uEndColor2; + uniform vec4 uEndColor3; + varying highp vec2 vUv; + void main() { + vec4 mask = texture2D(uTexture, vUv); + float r = mask.r; + float g = mask.g; + float b = mask.b; + float a = mask.a; + // If all channels have values, render pixel as a shade of white. + float useWhiteMask = step(cWhiteMaskThreshold, r) + * step(cWhiteMaskThreshold, g) + * step(cWhiteMaskThreshold, b) + * step(cWhiteMaskThreshold, a); + vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress) + + g * mix(uStartColor1, uEndColor1, uColorProgress) + + b * mix(uStartColor2, uEndColor2, uColorProgress) + + a * mix(uStartColor3, uEndColor3, uColorProgress); + color = mix(color, vec4(vec3((r + g + b + a) * 0.25), 1.0), useWhiteMask); + gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a; + })"; +static const char IMAGE_FRAG_SHADER_SOURCE[] = R"( + precision mediump float; + uniform sampler2D uTexture; + uniform float uFade; + varying highp vec2 vUv; + void main() { + vec4 color = texture2D(uTexture, vUv); + gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a; + })"; +static const char TEXT_FRAG_SHADER_SOURCE[] = R"( + precision mediump float; + uniform sampler2D uTexture; + uniform vec4 uCropArea; + varying highp vec2 vUv; + void main() { + vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x), + mix(uCropArea.y, uCropArea.w, vUv.y)); + gl_FragColor = texture2D(uTexture, uv); + })"; + +static GLfloat quadPositions[] = { + -0.5f, -0.5f, + +0.5f, -0.5f, + +0.5f, +0.5f, + +0.5f, +0.5f, + -0.5f, +0.5f, + -0.5f, -0.5f +}; +static GLfloat quadUVs[] = { + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 0.0f, + 0.0f, 1.0f +}; // --------------------------------------------------------------------------- @@ -163,7 +249,8 @@ void BootAnimation::binderDied(const wp<IBinder>&) { requestExit(); } -static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo) { +static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo, + bool premultiplyAlpha) { AImageDecoder* decoder = nullptr; AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder); if (!decoder) { @@ -177,6 +264,10 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm outInfo->stride = AImageDecoder_getMinimumStride(decoder); outInfo->flags = 0; + if (!premultiplyAlpha) { + AImageDecoder_setUnpremultipliedRequired(decoder, true); + } + const size_t size = outInfo->stride * outInfo->height; void* pixels = malloc(size); int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size); @@ -190,13 +281,14 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm } status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, - const char* name) { + const char* name, bool premultiplyAlpha) { Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); if (asset == nullptr) return NO_INIT; AndroidBitmapInfo bitmapInfo; - void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo); + void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo, + premultiplyAlpha); auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free }; asset->close(); @@ -209,7 +301,6 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, const int w = bitmapInfo.width; const int h = bitmapInfo.height; - GLint crop[4] = { 0, h, w, -h }; texture->w = w; texture->h = h; @@ -237,18 +328,19 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, break; } - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return NO_ERROR; } -status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { +status_t BootAnimation::initTexture(FileMap* map, int* width, int* height, + bool premultiplyAlpha) { AndroidBitmapInfo bitmapInfo; - void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo); + void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo, + premultiplyAlpha); auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free }; // FileMap memory is never released until application exit. @@ -263,7 +355,6 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { const int w = bitmapInfo.width; const int h = bitmapInfo.height; - GLint crop[4] = { 0, h, w, -h }; int tw = 1 << (31 - __builtin_clz(w)); int th = 1 << (31 - __builtin_clz(h)); if (tw < w) tw <<= 1; @@ -297,7 +388,10 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { break; } - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); *width = w; *height = h; @@ -470,7 +564,9 @@ status_t BootAnimation::readyToRun() { eglInitialize(display, nullptr, nullptr); EGLConfig config = getEglConfig(display); EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr); - EGLContext context = eglCreateContext(display, config, nullptr, nullptr); + // Initialize egl context with client version number 2.0. + EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes); EGLint w, h; eglQuerySurface(display, surface, EGL_WIDTH, &w); eglQuerySurface(display, surface, EGL_HEIGHT, &h); @@ -503,11 +599,6 @@ status_t BootAnimation::readyToRun() { void BootAnimation::projectSceneToWindow() { glViewport(0, 0, mWidth, mHeight); glScissor(0, 0, mWidth, mHeight); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); } void BootAnimation::resizeSurface(int newWidth, int newHeight) { @@ -600,8 +691,76 @@ void BootAnimation::findBootAnimationFile() { } } +GLuint compileShader(GLenum shaderType, const GLchar *source) { + GLuint shader = glCreateShader(shaderType); + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) { + SLOGE("Compile shader failed. Shader type: %d", shaderType); + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + std::vector<GLchar> errorLog(maxLength); + glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + SLOGE("Shader compilation error: %s", &errorLog[0]); + return 0; + } + return shader; +} + +GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) { + GLuint program = glCreateProgram(); + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked); + if (isLinked == GL_FALSE) { + SLOGE("Linking shader failed. Shader handles: vert %d, frag %d", + vertexShader, fragmentShader); + return 0; + } + return program; +} + +void BootAnimation::initShaders() { + bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled; + GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE); + GLuint imageFragmentShader = + compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled + ? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE + : (const GLchar *)IMAGE_FRAG_SHADER_SOURCE); + GLuint textFragmentShader = + compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE); + + // Initialize image shader. + mImageShader = linkShader(vertexShader, imageFragmentShader); + GLint positionLocation = glGetAttribLocation(mImageShader, A_POSITION); + GLint uvLocation = glGetAttribLocation(mImageShader, A_UV); + mImageTextureLocation = glGetUniformLocation(mImageShader, U_TEXTURE); + mImageFadeLocation = glGetUniformLocation(mImageShader, U_FADE); + glEnableVertexAttribArray(positionLocation); + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions); + glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs); + glEnableVertexAttribArray(uvLocation); + + // Initialize text shader. + mTextShader = linkShader(vertexShader, textFragmentShader); + positionLocation = glGetAttribLocation(mTextShader, A_POSITION); + uvLocation = glGetAttribLocation(mTextShader, A_UV); + mTextTextureLocation = glGetUniformLocation(mTextShader, U_TEXTURE); + mTextCropAreaLocation = glGetUniformLocation(mTextShader, U_CROP_AREA); + glEnableVertexAttribArray(positionLocation); + glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, quadPositions); + glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs); + glEnableVertexAttribArray(uvLocation); +} + bool BootAnimation::threadLoop() { bool result; + initShaders(); + // We have no bootanimation file, so we use the stock android logo // animation. if (mZipFileName.isEmpty()) { @@ -623,6 +782,8 @@ bool BootAnimation::threadLoop() { } bool BootAnimation::android() { + glActiveTexture(GL_TEXTURE0); + SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); @@ -631,19 +792,16 @@ bool BootAnimation::android() { mCallbacks->init({}); // clear screen - glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); + glUseProgram(mImageShader); + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mDisplay, mSurface); - glEnable(GL_TEXTURE_2D); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - // Blend state glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); const nsecs_t startTime = systemTime(); do { @@ -666,12 +824,12 @@ bool BootAnimation::android() { glEnable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); - glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h); - glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h); + drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h); + drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h); glEnable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[0].name); - glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h); + drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h); EGLBoolean res = eglSwapBuffers(mDisplay, mSurface); if (res == EGL_FALSE) @@ -766,6 +924,20 @@ static bool parseColor(const char str[7], float color[3]) { return true; } +// Parse a color represented as a signed decimal int string. +// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6). +// If the input color string is empty, set color with values in defaultColor. +static void parseColorDecimalString(const std::string& colorString, + float color[3], float defaultColor[3]) { + if (colorString == "") { + memcpy(color, defaultColor, sizeof(float) * 3); + return; + } + int colorInt = atoi(colorString.c_str()); + color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r + color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g + color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b +} static bool readFile(ZipFileRO* zip, const char* name, String8& outString) { ZipEntryRO entry = zip->findEntryByName(name); @@ -798,10 +970,10 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) { status = initTexture(font->map, &font->texture.w, &font->texture.h); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else if (fallback != nullptr) { status = initTexture(&font->texture, mAssets, fallback); } else { @@ -816,40 +988,11 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) { return status; } -void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth, - const int frameHeight, const Animation::Part& part, - const int fadedFramesCount) { - glEnable(GL_BLEND); - glEnableClientState(GL_VERTEX_ARRAY); - glDisable(GL_TEXTURE_2D); - // avoid creating a hole due to mixing result alpha with GL_REPLACE texture - glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - - const float alpha = static_cast<float>(fadedFramesCount) / part.framesToFadeCount; - glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha); - - const float frameStartX = static_cast<float>(frameLeft); - const float frameStartY = static_cast<float>(frameBottom); - const float frameEndX = frameStartX + frameWidth; - const float frameEndY = frameStartY + frameHeight; - const GLfloat frameRect[] = { - frameStartX, frameStartY, - frameEndX, frameStartY, - frameEndX, frameEndY, - frameStartX, frameEndY - }; - glVertexPointer(2, GL_FLOAT, 0, frameRect); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_TEXTURE_2D); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_BLEND); -} - void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) { glEnable(GL_BLEND); // Allow us to draw on top of the animation glBindTexture(GL_TEXTURE_2D, font.texture.name); + glUseProgram(mTextShader); + glUniform1i(mTextTextureLocation, 0); const int len = strlen(str); const int strWidth = font.char_width * len; @@ -865,8 +1008,6 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* *y = mHeight + *y - font.char_height; } - int cropRect[4] = { 0, 0, font.char_width, -font.char_height }; - for (int i = 0; i < len; i++) { char c = str[i]; @@ -878,13 +1019,13 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters const int row = charPos / FONT_NUM_COLS; const int col = charPos % FONT_NUM_COLS; - cropRect[0] = col * font.char_width; // Left of column - cropRect[1] = row * font.char_height * 2; // Top of row - // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line - cropRect[1] += bold ? 2 * font.char_height : font.char_height; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); - - glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height); + // Bold fonts are expected in the second half of each row. + float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS; + float u0 = ((float)col) / FONT_NUM_COLS; + float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2; + float u1 = u0 + 1.0f / FONT_NUM_COLS; + glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1); + drawTexturedQuad(*x, *y, font.char_width, font.char_height); *x += font.char_width; } @@ -938,6 +1079,8 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { return false; } char const* s = desString.string(); + std::string dynamicColoringPartName = ""; + bool postDynamicColoring = false; // Parse the description file for (;;) { @@ -952,11 +1095,19 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { int pause = 0; int progress = 0; int framesToFadeCount = 0; + int colorTransitionStart = 0; + int colorTransitionEnd = 0; char path[ANIM_ENTRY_NAME_MAX]; char color[7] = "000000"; // default to black if unspecified char clockPos1[TEXT_POS_LEN_MAX + 1] = ""; char clockPos2[TEXT_POS_LEN_MAX + 1] = ""; + char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX]; char pathType; + // start colors default to black if unspecified + char start_color_0[7] = "000000"; + char start_color_1[7] = "000000"; + char start_color_2[7] = "000000"; + char start_color_3[7] = "000000"; int nextReadPos; @@ -971,6 +1122,18 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { } else { animation.progressEnabled = false; } + } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s %d %d", + dynamicColoringPartNameBuffer, + start_color_0, start_color_1, start_color_2, start_color_3, + &colorTransitionStart, &colorTransitionEnd)) { + animation.dynamicColoringEnabled = true; + parseColor(start_color_0, animation.startColors[0]); + parseColor(start_color_1, animation.startColors[1]); + parseColor(start_color_2, animation.startColors[2]); + parseColor(start_color_3, animation.startColors[3]); + animation.colorTransitionStart = colorTransitionStart; + animation.colorTransitionEnd = colorTransitionEnd; + dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer); } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n", &pathType, &count, &pause, path, &nextReadPos) >= 4) { if (pathType == 'f') { @@ -983,6 +1146,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { // "clockPos1=%s, clockPos2=%s", // pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2); Animation::Part part; + if (path == dynamicColoringPartName) { + // Part is specified to use dynamic coloring. + part.useDynamicColoring = true; + part.postDynamicColoring = false; + postDynamicColoring = true; + } else { + // Part does not use dynamic coloring. + part.useDynamicColoring = false; + part.postDynamicColoring = postDynamicColoring; + } part.playUntilComplete = pathType == 'c'; part.framesToFadeCount = framesToFadeCount; part.count = count; @@ -1166,19 +1339,16 @@ bool BootAnimation::movie() { // Blend required to draw time on top of animation frames. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); - glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_TEXTURE_2D); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - + glBindTexture(GL_TEXTURE_2D, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); bool clockFontInitialized = false; if (mClockEnabled) { clockFontInitialized = @@ -1193,6 +1363,10 @@ bool BootAnimation::movie() { mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL); } + if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) { + initDynamicColors(); + } + playAnimation(*mAnimation); if (mTimeCheckThread != nullptr) { @@ -1218,6 +1392,55 @@ bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part, (lastDisplayedProgress == 0 || lastDisplayedProgress == 100); } +// Linear mapping from range <a1, a2> to range <b1, b2> +float mapLinear(float x, float a1, float a2, float b1, float b2) { + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); +} + +void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) { + // Map coordinates from screen space to world space. + float x0 = mapLinear(xStart, 0, mWidth, -1, 1); + float y0 = mapLinear(yStart, 0, mHeight, -1, 1); + float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1); + float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1); + // Update quad vertex positions. + quadPositions[0] = x0; + quadPositions[1] = y0; + quadPositions[2] = x1; + quadPositions[3] = y0; + quadPositions[4] = x1; + quadPositions[5] = y1; + quadPositions[6] = x1; + quadPositions[7] = y1; + quadPositions[8] = x0; + quadPositions[9] = y1; + quadPositions[10] = x0; + quadPositions[11] = y0; + glDrawArrays(GL_TRIANGLES, 0, + sizeof(quadPositions) / sizeof(quadPositions[0]) / 2); +} + +void BootAnimation::initDynamicColors() { + for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { + parseColorDecimalString( + android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""), + mAnimation->endColors[i], mAnimation->startColors[i]); + } + glUseProgram(mImageShader); + SLOGI("[BootAnimation] Dynamically coloring boot animation."); + for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { + float *startColor = mAnimation->startColors[i]; + float *endColor = mAnimation->endColors[i]; + glUniform4f(glGetUniformLocation(mImageShader, + (U_START_COLOR_PREFIX + std::to_string(i)).c_str()), + startColor[0], startColor[1], startColor[2], 1 /* alpha */); + glUniform4f(glGetUniformLocation(mImageShader, + (U_END_COLOR_PREFIX + std::to_string(i)).c_str()), + endColor[0], endColor[1], endColor[2], 1 /* alpha */); + } + mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS); +} + bool BootAnimation::playAnimation(const Animation& animation) { const size_t pcount = animation.parts.size(); nsecs_t frameDuration = s2ns(1) / animation.fps; @@ -1230,7 +1453,6 @@ bool BootAnimation::playAnimation(const Animation& animation) { for (size_t i=0 ; i<pcount ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); - glBindTexture(GL_TEXTURE_2D, 0); // Handle animation package if (part.animation != nullptr) { @@ -1261,6 +1483,19 @@ bool BootAnimation::playAnimation(const Animation& animation) { for (size_t j=0 ; j<fcount ; j++) { if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break; + // Color progress is + // - the animation progress, normalized from + // [colorTransitionStart,colorTransitionEnd] to [0, 1] for the dynamic coloring + // part. + // - 0 for parts that come before, + // - 1 for parts that come after. + float colorProgress = part.useDynamicColoring + ? fmin(fmax( + ((float)j - animation.colorTransitionStart) / + fmax(animation.colorTransitionEnd - + animation.colorTransitionStart, 1.0f), 0.0f), 1.0f) + : (part.postDynamicColoring ? 1 : 0); + processDisplayEvents(); const int animationX = (mWidth - animation.width) / 2; @@ -1272,44 +1507,38 @@ bool BootAnimation::playAnimation(const Animation& animation) { if (r > 0) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { - if (part.count != 1) { - glGenTextures(1, &frame.tid); - glBindTexture(GL_TEXTURE_2D, frame.tid); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } + glGenTextures(1, &frame.tid); + glBindTexture(GL_TEXTURE_2D, frame.tid); int w, h; - initTexture(frame.map, &w, &h); + // Set decoding option to alpha unpremultiplied so that the R, G, B channels + // of transparent pixels are preserved. + initTexture(frame.map, &w, &h, false /* don't premultiply alpha */); } const int xc = animationX + frame.trimX; const int yc = animationY + frame.trimY; - Region clearReg(Rect(mWidth, mHeight)); - clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight)); - if (!clearReg.isEmpty()) { - Region::const_iterator head(clearReg.begin()); - Region::const_iterator tail(clearReg.end()); - glEnable(GL_SCISSOR_TEST); - while (head != tail) { - const Rect& r2(*head++); - glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height()); - glClear(GL_COLOR_BUFFER_BIT); - } - glDisable(GL_SCISSOR_TEST); - } + glClear(GL_COLOR_BUFFER_BIT); // specify the y center as ceiling((mHeight - frame.trimHeight) / 2) // which is equivalent to mHeight - (yc + frame.trimHeight) const int frameDrawY = mHeight - (yc + frame.trimHeight); - glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight); + float fade = 0; // if the part hasn't been stopped yet then continue fading if necessary if (exitPending() && part.hasFadingPhase()) { - fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part, - ++fadedFramesCount); + fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount; if (fadedFramesCount >= part.framesToFadeCount) { fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading } } + glUseProgram(mImageShader); + glUniform1i(mImageTextureLocation, 0); + glUniform1f(mImageFadeLocation, fade); + if (animation.dynamicColoringEnabled) { + glUniform1f(mImageColorProgressLocation, colorProgress); + } + glEnable(GL_BLEND); + drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight); + glDisable(GL_BLEND); if (mClockEnabled && mTimeIsAccurate && validClock(part)) { drawClock(animation.clockFont, part.clockPosX, part.clockPosY); diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index f8a31c6d8790..7a597da533ee 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -31,7 +31,7 @@ #include <binder/IBinder.h> #include <EGL/egl.h> -#include <GLES/gl.h> +#include <GLES2/gl2.h> namespace android { @@ -53,7 +53,7 @@ public: }; struct Font { - FileMap* map; + FileMap* map = nullptr; Texture texture; int char_width; int char_height; @@ -62,7 +62,7 @@ public: struct Animation { struct Frame { String8 name; - FileMap* map; + FileMap* map = nullptr; int trimX; int trimY; int trimWidth; @@ -90,6 +90,10 @@ public: uint8_t* audioData; int audioLength; Animation* animation; + // Controls if dynamic coloring is enabled for this part. + bool useDynamicColoring = false; + // Defines if this part is played after the dynamic coloring part. + bool postDynamicColoring = false; bool hasFadingPhase() const { return !playUntilComplete && framesToFadeCount > 0; @@ -105,6 +109,12 @@ public: ZipFileRO* zip; Font clockFont; Font progressFont; + // Controls if dynamic coloring is enabled for the whole animation. + bool dynamicColoringEnabled = false; + int colorTransitionStart = 0; // Start frame of dynamic color transition. + int colorTransitionEnd = 0; // End frame of dynamic color transition. + float startColors[4][3]; // Start colors of dynamic color transition. + float endColors[4][3]; // End colors of dynamic color transition. }; // All callbacks will be called from this class's internal thread. @@ -163,9 +173,12 @@ private: int displayEventCallback(int fd, int events, void* data); void processDisplayEvents(); - status_t initTexture(Texture* texture, AssetManager& asset, const char* name); - status_t initTexture(FileMap* map, int* width, int* height); + status_t initTexture(Texture* texture, AssetManager& asset, const char* name, + bool premultiplyAlpha = true); + status_t initTexture(FileMap* map, int* width, int* height, + bool premultiplyAlpha = true); status_t initFont(Font* font, const char* fallback); + void initShaders(); bool android(); bool movie(); void drawText(const char* str, const Font& font, bool bold, int* x, int* y); @@ -173,6 +186,7 @@ private: void drawProgress(int percent, const Font& font, const int xPos, const int yPos); void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight, const Animation::Part& part, int fadedFramesCount); + void drawTexturedQuad(float xStart, float yStart, float width, float height); bool validClock(const Animation::Part& part); Animation* loadAnimation(const String8&); bool playAnimation(const Animation&); @@ -192,6 +206,7 @@ private: void checkExit(); void handleViewport(nsecs_t timestep); + void initDynamicColors(); sp<SurfaceComposerClient> mSession; AssetManager mAssets; @@ -218,6 +233,13 @@ private: sp<TimeCheckThread> mTimeCheckThread = nullptr; sp<Callbacks> mCallbacks; Animation* mAnimation = nullptr; + GLuint mImageShader; + GLuint mTextShader; + GLuint mImageFadeLocation; + GLuint mImageTextureLocation; + GLuint mTextCropAreaLocation; + GLuint mTextTextureLocation; + GLuint mImageColorProgressLocation; }; // --------------------------------------------------------------------------- diff --git a/cmds/bootanimation/OWNERS b/cmds/bootanimation/OWNERS new file mode 100644 index 000000000000..b6fb007bea52 --- /dev/null +++ b/cmds/bootanimation/OWNERS @@ -0,0 +1,3 @@ +dupin@google.com +shanh@google.com +jreck@google.com diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java index 5964f71d28db..babeb08caff7 100644 --- a/core/java/android/app/GameManager.java +++ b/core/java/android/app/GameManager.java @@ -135,6 +135,7 @@ public final class GameManager { throw e.rethrowFromSystemServer(); } } + /** * Returns a list of supported game modes for a given package. * <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(); + } + } } diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl index 4bf8a3f77bca..189f0a2fca23 100644 --- a/core/java/android/app/IGameManagerService.aidl +++ b/core/java/android/app/IGameManagerService.aidl @@ -23,4 +23,5 @@ interface IGameManagerService { int getGameMode(String packageName, int userId); void setGameMode(String packageName, int gameMode, int userId); int[] getAvailableGameModes(String packageName); + boolean getAngleEnabled(String packageName, int userId); }
\ No newline at end of file diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 4b054f49d910..719025f9e215 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1884,6 +1884,14 @@ public class Notification implements Parcelable * clicks. To launch an activity in those cases, provide a {@link PendingIntent} for the * activity itself. * + * <p>How an Action is displayed, including whether the {@code icon}, {@code text}, or + * both are displayed or required, depends on where and how the action is used, and the + * {@link Style} applied to the Notification. + * + * <p>When the {@code title} is a {@link android.text.Spanned}, any colors set by a + * {@link ForegroundColorSpan} or {@link TextAppearanceSpan} may be removed or displayed + * with an altered in luminance to ensure proper contrast within the Notification. + * * @param icon icon to show for this action * @param title the title of the action * @param intent the {@link PendingIntent} to fire when users trigger this action @@ -5387,8 +5395,8 @@ public class Notification implements Parcelable contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor); // Use different highlighted colors for conversations' unread count if (p.mHighlightExpander) { - pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor); - textColor = Colors.flattenAlpha(bgColor, pillColor); + pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor); + textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor); } contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor); contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor); @@ -6121,21 +6129,22 @@ public class Notification implements Parcelable if (emphasizedMode) { // change the background bgColor CharSequence title = action.title; - ColorStateList[] outResultColor = new ColorStateList[1]; int buttonFillColor = getColors(p).getSecondaryAccentColor(); if (isLegacy()) { title = ContrastColorUtil.clearColorSpans(title); } else { - int notifBackgroundColor = getColors(p).getBackgroundColor(); - title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor); + // Check for a full-length span color to use as the button fill color. + Integer fullLengthColor = getFullLengthSpanColor(title); + if (fullLengthColor != null) { + // Ensure the custom button fill has 1.3:1 contrast w/ notification bg. + int notifBackgroundColor = getColors(p).getBackgroundColor(); + buttonFillColor = ensureButtonFillContrast( + fullLengthColor, notifBackgroundColor); + } + // Remove full-length color spans and ensure text contrast with the button fill. + title = ensureColorSpanContrast(title, buttonFillColor); } button.setTextViewText(R.id.action0, processTextSpans(title)); - boolean hasColorOverride = outResultColor[0] != null; - if (hasColorOverride) { - // There's a span spanning the full text, let's take it and use it as the - // background color - buttonFillColor = outResultColor[0].getDefaultColor(); - } final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext, buttonFillColor, mInNightMode); button.setTextColor(R.id.action0, textColor); @@ -6168,17 +6177,58 @@ public class Notification implements Parcelable } /** - * Ensures contrast on color spans against a background color. also returns the color of the - * text if a span was found that spans over the whole text. + * Extract the color from a full-length span from the text. + * + * @param charSequence the charSequence containing spans + * @return the raw color of the text's last full-length span containing a color, or null if + * no full-length span sets the text color. + * @hide + */ + @VisibleForTesting + @Nullable + public static Integer getFullLengthSpanColor(CharSequence charSequence) { + // NOTE: this method preserves the functionality that for a CharSequence with multiple + // full-length spans, the color of the last one is used. + Integer result = null; + if (charSequence instanceof Spanned) { + Spanned ss = (Spanned) charSequence; + Object[] spans = ss.getSpans(0, ss.length(), Object.class); + // First read through all full-length spans to get the button fill color, which will + // be used as the background color for ensuring contrast of non-full-length spans. + for (Object span : spans) { + int spanStart = ss.getSpanStart(span); + int spanEnd = ss.getSpanEnd(span); + boolean fullLength = (spanEnd - spanStart) == charSequence.length(); + if (!fullLength) { + continue; + } + if (span instanceof TextAppearanceSpan) { + TextAppearanceSpan originalSpan = (TextAppearanceSpan) span; + ColorStateList textColor = originalSpan.getTextColor(); + if (textColor != null) { + result = textColor.getDefaultColor(); + } + } else if (span instanceof ForegroundColorSpan) { + ForegroundColorSpan originalSpan = (ForegroundColorSpan) span; + result = originalSpan.getForegroundColor(); + } + } + } + return result; + } + + /** + * Ensures contrast on color spans against a background color. + * Note that any full-length color spans will be removed instead of being contrasted. * * @param charSequence the charSequence on which the spans are * @param background the background color to ensure the contrast against - * @param outResultColor an array in which a color will be returned as the first element if - * there exists a full length color span. * @return the contrasted charSequence + * @hide */ - private static CharSequence ensureColorSpanContrast(CharSequence charSequence, - int background, ColorStateList[] outResultColor) { + @VisibleForTesting + public static CharSequence ensureColorSpanContrast(CharSequence charSequence, + int background) { if (charSequence instanceof Spanned) { Spanned ss = (Spanned) charSequence; Object[] spans = ss.getSpans(0, ss.length(), Object.class); @@ -6195,19 +6245,19 @@ public class Notification implements Parcelable TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; ColorStateList textColor = originalSpan.getTextColor(); if (textColor != null) { - int[] colors = textColor.getColors(); - int[] newColors = new int[colors.length]; - for (int i = 0; i < newColors.length; i++) { - boolean isBgDark = isColorDark(background); - newColors[i] = ContrastColorUtil.ensureLargeTextContrast( - colors[i], background, isBgDark); - } - textColor = new ColorStateList(textColor.getStates().clone(), - newColors); if (fullLength) { - outResultColor[0] = textColor; // Let's drop the color from the span textColor = null; + } else { + int[] colors = textColor.getColors(); + int[] newColors = new int[colors.length]; + for (int i = 0; i < newColors.length; i++) { + boolean isBgDark = isColorDark(background); + newColors[i] = ContrastColorUtil.ensureLargeTextContrast( + colors[i], background, isBgDark); + } + textColor = new ColorStateList(textColor.getStates().clone(), + newColors); } resultSpan = new TextAppearanceSpan( originalSpan.getFamily(), @@ -6217,15 +6267,14 @@ public class Notification implements Parcelable originalSpan.getLinkTextColor()); } } else if (resultSpan instanceof ForegroundColorSpan) { - ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan; - int foregroundColor = originalSpan.getForegroundColor(); - boolean isBgDark = isColorDark(background); - foregroundColor = ContrastColorUtil.ensureLargeTextContrast( - foregroundColor, background, isBgDark); if (fullLength) { - outResultColor[0] = ColorStateList.valueOf(foregroundColor); resultSpan = null; } else { + ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan; + int foregroundColor = originalSpan.getForegroundColor(); + boolean isBgDark = isColorDark(background); + foregroundColor = ContrastColorUtil.ensureLargeTextContrast( + foregroundColor, background, isBgDark); resultSpan = new ForegroundColorSpan(foregroundColor); } } else { @@ -6247,13 +6296,29 @@ public class Notification implements Parcelable * * @param color the color to check * @return true if the color has higher contrast with white than black + * @hide */ - private static boolean isColorDark(int color) { + public static boolean isColorDark(int color) { // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint. return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474; } /** + * Finds a button fill color with sufficient contrast over bg (1.3:1) that has the same hue + * as the original color, but is lightened or darkened depending on whether the background + * is dark or light. + * + * @hide + */ + @VisibleForTesting + public static int ensureButtonFillContrast(int color, int bg) { + return isColorDark(bg) + ? ContrastColorUtil.findContrastColorAgainstDark(color, bg, true, 1.3) + : ContrastColorUtil.findContrastColor(color, bg, true, 1.3); + } + + + /** * @return Whether we are currently building a notification from a legacy (an app that * doesn't create material notifications by itself) app. */ @@ -12305,6 +12370,8 @@ public class Notification implements Parcelable private int mSecondaryTextColor = COLOR_INVALID; private int mPrimaryAccentColor = COLOR_INVALID; private int mSecondaryAccentColor = COLOR_INVALID; + private int mTertiaryAccentColor = COLOR_INVALID; + private int mOnAccentTextColor = COLOR_INVALID; private int mErrorColor = COLOR_INVALID; private int mContrastColor = COLOR_INVALID; private int mRippleAlpha = 0x33; @@ -12362,7 +12429,7 @@ public class Notification implements Parcelable if (isColorized) { if (rawColor == COLOR_DEFAULT) { - int[] attrs = {R.attr.colorAccentTertiary}; + int[] attrs = {R.attr.colorAccentSecondary}; try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { mBackgroundColor = getColor(ta, 0, Color.WHITE); } @@ -12379,6 +12446,8 @@ public class Notification implements Parcelable mContrastColor = mPrimaryTextColor; mPrimaryAccentColor = mPrimaryTextColor; mSecondaryAccentColor = mSecondaryTextColor; + mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor); + mOnAccentTextColor = mBackgroundColor; mErrorColor = mPrimaryTextColor; mRippleAlpha = 0x33; } else { @@ -12389,6 +12458,8 @@ public class Notification implements Parcelable R.attr.textColorSecondary, R.attr.colorAccent, R.attr.colorAccentSecondary, + R.attr.colorAccentTertiary, + R.attr.textColorOnAccent, R.attr.colorError, R.attr.colorControlHighlight }; @@ -12399,8 +12470,10 @@ public class Notification implements Parcelable mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID); mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID); mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID); - mErrorColor = getColor(ta, 6, COLOR_INVALID); - mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff)); + mTertiaryAccentColor = getColor(ta, 6, COLOR_INVALID); + mOnAccentTextColor = getColor(ta, 7, COLOR_INVALID); + mErrorColor = getColor(ta, 8, COLOR_INVALID); + mRippleAlpha = Color.alpha(getColor(ta, 9, 0x33ffffff)); } mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor, mBackgroundColor, nightMode); @@ -12420,6 +12493,14 @@ public class Notification implements Parcelable if (mSecondaryAccentColor == COLOR_INVALID) { mSecondaryAccentColor = mContrastColor; } + if (mTertiaryAccentColor == COLOR_INVALID) { + mTertiaryAccentColor = mContrastColor; + } + if (mOnAccentTextColor == COLOR_INVALID) { + mOnAccentTextColor = ColorUtils.setAlphaComponent( + ContrastColorUtil.resolvePrimaryColor( + ctx, mTertiaryAccentColor, nightMode), 0xFF); + } if (mErrorColor == COLOR_INVALID) { mErrorColor = mPrimaryTextColor; } @@ -12485,6 +12566,16 @@ public class Notification implements Parcelable return mSecondaryAccentColor; } + /** @return the theme's tertiary accent color for colored UI elements. */ + public @ColorInt int getTertiaryAccentColor() { + return mTertiaryAccentColor; + } + + /** @return the theme's text color to be used on the tertiary accent color. */ + public @ColorInt int getOnAccentTextColor() { + return mOnAccentTextColor; + } + /** * @return the contrast-adjusted version of the color provided by the app, or the * primary text color when colorized. diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 1837fb860b73..6553b61ebbc2 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -260,8 +260,6 @@ public final class NotificationChannel implements Parcelable { private boolean mDemoted = false; private boolean mImportantConvo = false; private long mDeletedTime = DEFAULT_DELETION_TIME_MS; - // If the sound for this channel is missing, e.g. after restore. - private boolean mIsSoundMissing; /** * Creates a notification channel. @@ -717,13 +715,6 @@ public final class NotificationChannel implements Parcelable { } /** - * @hide - */ - public boolean isSoundMissing() { - return mIsSoundMissing; - } - - /** * Returns the audio attributes for sound played by notifications posted to this channel. */ public AudioAttributes getAudioAttributes() { @@ -1007,9 +998,8 @@ public final class NotificationChannel implements Parcelable { // according to the docs because canonicalize method has to handle canonical uris as well. Uri canonicalizedUri = contentResolver.canonicalize(uri); if (canonicalizedUri == null) { - // We got a null because the uri in the backup does not exist here. - mIsSoundMissing = true; - return null; + // We got a null because the uri in the backup does not exist here, so we return default + return Settings.System.DEFAULT_NOTIFICATION_URI; } return contentResolver.uncanonicalize(canonicalizedUri); } diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index dae565e12fd7..67f631f98f0b 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -281,6 +281,32 @@ public class BackupManager { } /** + * Convenience method for callers who need to indicate that some other package or + * some other user needs a backup pass. This can be useful in the case of groups of + * packages that share a uid and/or have user-specific data. + * <p> + * This method requires that the application hold the "android.permission.BACKUP" + * permission if the package named in the package argument does not run under the + * same uid as the caller. This method also requires that the application hold the + * "android.permission.INTERACT_ACROSS_USERS_FULL" if the user argument is not the + * same as the user the caller is running under. + * @param userId The user to back up + * @param packageName The package name identifying the application to back up. + * + * @hide + */ + public static void dataChangedForUser(int userId, String packageName) { + checkServiceBinder(); + if (sService != null) { + try { + sService.dataChangedForUser(userId, packageName); + } catch (RemoteException e) { + Log.e(TAG, "dataChanged(userId,pkg) couldn't connect"); + } + } + } + + /** * @deprecated Applications shouldn't request a restore operation using this method. In Android * P and later, this method is a no-op. * diff --git a/core/java/android/app/search/Query.java b/core/java/android/app/search/Query.java index c64e10723ca6..f073b4e50555 100644 --- a/core/java/android/app/search/Query.java +++ b/core/java/android/app/search/Query.java @@ -70,7 +70,7 @@ public final class Query implements Parcelable { @NonNull Bundle extras) { mInput = input; mTimestampMillis = timestampMillis; - mExtras = extras == null ? extras : new Bundle(); + mExtras = extras != null ? extras : new Bundle(); } /** diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 3f3db29ed0fd..c8c122da4ab8 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -438,9 +438,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener { + private final long mAuthRequestId; + + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelAuthentication(); + Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } @@ -853,10 +860,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @param userId The user to authenticate * @param operationId The keystore operation associated with authentication * + * @return A requestId that can be used to cancel this operation. + * * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) - public void authenticateUserForOperation( + public long authenticateUserForOperation( @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback, @@ -871,7 +880,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan if (callback == null) { throw new IllegalArgumentException("Must supply a callback"); } - authenticateInternal(operationId, cancel, executor, callback, userId); + + return authenticateInternal(operationId, cancel, executor, callback, userId); } /** @@ -1002,10 +1012,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId()); } - private void cancelAuthentication() { + private void cancelAuthentication(long requestId) { if (mService != null) { try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { Log.e(TAG, "Unable to cancel authentication", e); } @@ -1024,7 +1034,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan authenticateInternal(operationId, cancel, executor, callback, userId); } - private void authenticateInternal( + private long authenticateInternal( long operationId, @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @@ -1040,9 +1050,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan try { if (cancel.isCanceled()) { Log.w(TAG, "Authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener()); + return -1; } mExecutor = executor; @@ -1065,14 +1073,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan promptInfo = mPromptInfo; } - mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, - mContext.getOpPackageName(), promptInfo); - + final long authId = mService.authenticate(mToken, operationId, userId, + mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo); + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + return authId; } catch (RemoteException e) { Log.e(TAG, "Remote exception while authenticating", e); mExecutor.execute(() -> callback.onAuthenticationError( BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, mContext.getString(R.string.biometric_error_hw_unavailable))); + return -1; } } diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl index 4c2a9ae10cbd..91f794c161bf 100644 --- a/core/java/android/hardware/biometrics/IAuthService.aidl +++ b/core/java/android/hardware/biometrics/IAuthService.aidl @@ -41,13 +41,14 @@ interface IAuthService { // Retrieve the package where BIometricOrompt's UI is implemented String getUiPackage(); - // Requests authentication. The service choose the appropriate biometric to use, and show - // the corresponding BiometricDialog. - void authenticate(IBinder token, long sessionId, int userId, + // Requests authentication. The service chooses the appropriate biometric to use, and shows + // the corresponding BiometricDialog. A requestId is returned that can be used to cancel + // this operation. + long authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics. // Checks if biometrics can be used. diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index 876513f266e8..addd622eef35 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -48,13 +48,13 @@ interface IBiometricAuthenticator { // startPreparedClient(). void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication); + long requestId, int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int cookie); - // Cancels authentication. - void cancelAuthenticationFromService(IBinder token, String opPackageName); + // Cancels authentication for the given requestId. + void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId); // Determine if HAL is loaded and ready boolean isHardwareDetected(String opPackageName); diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl index 64b51183a170..2c3c8c353e8c 100644 --- a/core/java/android/hardware/biometrics/IBiometricService.aidl +++ b/core/java/android/hardware/biometrics/IBiometricService.aidl @@ -36,13 +36,14 @@ interface IBiometricService { // Retrieve static sensor properties for all biometric sensors List<SensorPropertiesInternal> getSensorProperties(String opPackageName); - // Requests authentication. The service choose the appropriate biometric to use, and show - // the corresponding BiometricDialog. - void authenticate(IBinder token, long operationId, int userId, + // Requests authentication. The service chooses the appropriate biometric to use, and shows + // the corresponding BiometricDialog. A requestId is returned that can be used to cancel + // this operation. + long authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); - // Cancel authentication for the given session. - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); // Checks if biometrics can be used. int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators); diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index a9b95fce8777..6c3936569c28 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -361,6 +361,11 @@ public final class DisplayManagerGlobal { for (int i = 0; i < numListeners; i++) { mask |= mDisplayListeners.get(i).mEventsMask; } + if (mDispatchNativeCallbacks) { + mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED + | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; + } return mask; } @@ -1047,12 +1052,17 @@ public final class DisplayManagerGlobal { private static native void nSignalNativeCallbacks(float refreshRate); - // Called from AChoreographer via JNI. - // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. - private void registerNativeChoreographerForRefreshRateCallbacks() { + /** + * Called from AChoreographer via JNI. + * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. + * Public for unit testing to be able to call this method. + */ + @VisibleForTesting + public void registerNativeChoreographerForRefreshRateCallbacks() { synchronized (mLock) { - registerCallbackIfNeededLocked(); mDispatchNativeCallbacks = true; + registerCallbackIfNeededLocked(); + updateCallbackIfNeededLocked(); DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); if (display != null) { // We need to tell AChoreographer instances the current refresh rate so that apps @@ -1063,11 +1073,16 @@ public final class DisplayManagerGlobal { } } - // Called from AChoreographer via JNI. - // Unregisters AChoreographer from receiving refresh rate callbacks. - private void unregisterNativeChoreographerForRefreshRateCallbacks() { + /** + * Called from AChoreographer via JNI. + * Unregisters AChoreographer from receiving refresh rate callbacks. + * Public for unit testing to be able to call this method. + */ + @VisibleForTesting + public void unregisterNativeChoreographerForRefreshRateCallbacks() { synchronized (mLock) { mDispatchNativeCallbacks = false; + updateCallbackIfNeededLocked(); } } } diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 385ad2d3577f..56f81423db4e 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -58,7 +58,7 @@ import java.util.List; public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants { private static final String TAG = "FaceManager"; - private static final boolean DEBUG = true; + private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; @@ -207,13 +207,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan throw new IllegalArgumentException("Must supply an authentication callback"); } - if (cancel != null) { - if (cancel.isCanceled()) { - Slog.w(TAG, "authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); - } + if (cancel != null && cancel.isCanceled()) { + Slog.w(TAG, "authentication already canceled"); + return; } if (mService != null) { @@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; Trace.beginSection("FaceManager#authenticate"); - mService.authenticate(mToken, operationId, userId, mServiceReceiver, - mContext.getOpPackageName(), isKeyguardBypassEnabled); + final long authId = mService.authenticate(mToken, operationId, userId, + mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled); + if (cancel != null) { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + } } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); - if (callback != null) { - // Though this may not be a hardware issue, it will cause apps to give up or - // try again later. - callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, - getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */)); - } + // Though this may not be a hardware issue, it will cause apps to give up or + // try again later. + callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, + getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */)); } finally { Trace.endSection(); } @@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (cancel.isCanceled()) { Slog.w(TAG, "Detection already cancelled"); return; - } else { - cancel.setOnCancelListener(new OnFaceDetectionCancelListener()); } mFaceDetectionCallback = callback; try { - mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + final long authId = mService.detectFace( + mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); } @@ -726,23 +723,23 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } } - private void cancelAuthentication(CryptoObject cryptoObject) { + private void cancelAuthentication(long requestId) { if (mService != null) { try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } - private void cancelFaceDetect() { + private void cancelFaceDetect(long requestId) { if (mService == null) { return; } try { - mService.cancelFaceDetect(mToken, mContext.getOpPackageName()); + mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -794,9 +791,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan // This is used as a last resort in case a vendor string is missing // It should not happen for anything other than FACE_ERROR_VENDOR, but // warn and use the default if all else fails. - // TODO(b/196639965): update string Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); - return ""; + return context.getString( + com.android.internal.R.string.face_error_vendor_unknown); } /** @@ -1110,22 +1107,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } private class OnAuthenticationCancelListener implements OnCancelListener { - private final CryptoObject mCrypto; + private final long mAuthRequestId; - OnAuthenticationCancelListener(CryptoObject crypto) { - mCrypto = crypto; + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; } @Override public void onCancel() { - cancelAuthentication(mCrypto); + Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } private class OnFaceDetectionCancelListener implements OnCancelListener { + private final long mAuthRequestId; + + OnFaceDetectionCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelFaceDetect(); + Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId); + cancelFaceDetect(mAuthRequestId); } } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index db02a0ef2a10..e9198246dee3 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -44,34 +44,36 @@ interface IFaceService { // Retrieve static sensor properties for the specified sensor FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); - // Authenticate the given sessionId with a face - void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, + // Authenticate with a face. A requestId is returned that can be used to cancel this operation. + long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, String opPackageName, boolean isKeyguardBypassEnabled); // Uses the face hardware to detect for the presence of a face, without giving details - // about accept/reject/lockout. - void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); + // about accept/reject/lockout. A requestId is returned that can be used to cancel this + // operation. + long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be // called from BiometricService. The additional uid, pid, userId arguments should be determined // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). - void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, - int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication); + void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, + long operationId, int userId, IBiometricSensorReceiver sensorReceiver, + String opPackageName, long requestId, int cookie, + boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); - // Cancel face detection - void cancelFaceDetect(IBinder token, String opPackageName); + // Cancel face detection for the given requestId. + void cancelFaceDetect(IBinder token, String opPackageName, long requestId); // Same as above, with extra arguments. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId); // Start face enrollment void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 87d45b9de745..d48d562b6692 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -189,22 +189,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } private class OnAuthenticationCancelListener implements OnCancelListener { - private android.hardware.biometrics.CryptoObject mCrypto; + private final long mAuthRequestId; - public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { - mCrypto = crypto; + OnAuthenticationCancelListener(long id) { + mAuthRequestId = id; } @Override public void onCancel() { - cancelAuthentication(mCrypto); + Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId); + cancelAuthentication(mAuthRequestId); } } private class OnFingerprintDetectionCancelListener implements OnCancelListener { + private final long mAuthRequestId; + + OnFingerprintDetectionCancelListener(long id) { + mAuthRequestId = id; + } + @Override public void onCancel() { - cancelFingerprintDetect(); + Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId); + cancelFingerprintDetect(mAuthRequestId); } } @@ -552,13 +560,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing throw new IllegalArgumentException("Must supply an authentication callback"); } - if (cancel != null) { - if (cancel.isCanceled()) { - Slog.w(TAG, "authentication already canceled"); - return; - } else { - cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); - } + if (cancel != null && cancel.isCanceled()) { + Slog.w(TAG, "authentication already canceled"); + return; } if (mService != null) { @@ -567,8 +571,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing mAuthenticationCallback = callback; mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; - mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver, - mContext.getOpPackageName()); + final long authId = mService.authenticate(mToken, operationId, sensorId, userId, + mServiceReceiver, mContext.getOpPackageName()); + if (cancel != null) { + cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); + } } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); // Though this may not be a hardware issue, it will cause apps to give up or try @@ -595,15 +602,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing if (cancel.isCanceled()) { Slog.w(TAG, "Detection already cancelled"); return; - } else { - cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener()); } mFingerprintDetectionCallback = callback; try { - mService.detectFingerprint(mToken, userId, mServiceReceiver, + final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); + cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId)); } catch (RemoteException e) { Slog.w(TAG, "Remote exception when requesting finger detect", e); } @@ -844,26 +850,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * 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 */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @@ -1320,21 +1306,21 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } - private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) { + private void cancelAuthentication(long requestId) { if (mService != null) try { - mService.cancelAuthentication(mToken, mContext.getOpPackageName()); + mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - private void cancelFingerprintDetect() { + private void cancelFingerprintDetect(long requestId) { if (mService == null) { return; } try { - mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName()); + mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1390,9 +1376,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing // This is used as a last resort in case a vendor string is missing // It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but // warn and use the default if all else fails. - // TODO(b/196639965): update string Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode); - return ""; + return context.getString( + com.android.internal.R.string.fingerprint_error_vendor_unknown); } /** diff --git a/core/java/android/hardware/fingerprint/FingerprintStateListener.java b/core/java/android/hardware/fingerprint/FingerprintStateListener.java index 6e607a269cb2..cf914c5acd1a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintStateListener.java +++ b/core/java/android/hardware/fingerprint/FingerprintStateListener.java @@ -49,5 +49,10 @@ public abstract class FingerprintStateListener extends IFingerprintStateListener * Defines behavior in response to state update * @param newState new state of fingerprint sensor */ - public abstract void onStateChanged(@FingerprintStateListener.State int newState); + public void onStateChanged(@FingerprintStateListener.State int newState) {}; + + /** + * Invoked when enrollment state changes for the specified user + */ + public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {}; } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3979afe80d17..de94b2fbb5b5 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -48,15 +48,16 @@ interface IFingerprintService { // Retrieve static sensor properties for the specified sensor FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); - // Authenticate the given sessionId with a fingerprint. This is protected by - // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes - // through FingerprintManager now. - void authenticate(IBinder token, long operationId, int sensorId, int userId, + // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC + // permission. This is effectively deprecated, since it only comes through FingerprintManager + // now. A requestId is returned that can be used to cancel this operation. + long authenticate(IBinder token, long operationId, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName); // Uses the fingerprint hardware to detect for the presence of a finger, without giving details - // about accept/reject/lockout. - void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, + // about accept/reject/lockout. A requestId is returned that can be used to cancel this + // operation. + long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. @@ -65,21 +66,21 @@ interface IFingerprintService { // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - boolean allowBackgroundAuthentication); + IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, + int cookie, boolean allowBackgroundAuthentication); // Starts authentication with the previously prepared client. void startPreparedClient(int sensorId, int cookie); - // Cancel authentication for the given sessionId - void cancelAuthentication(IBinder token, String opPackageName); + // Cancel authentication for the given requestId. + void cancelAuthentication(IBinder token, String opPackageName, long requestId); - // Cancel finger detection - void cancelFingerprintDetect(IBinder token, String opPackageName); + // Cancel finger detection for the given requestId. + void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId); // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // an additional uid, pid, userid. - void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); + void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId); // Start fingerprint enrollment void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, @@ -119,9 +120,6 @@ interface IFingerprintService { // Determine if a user has at least one enrolled fingerprint. boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName); - // Determine if a user has at least one enrolled fingerprint in any of the specified sensors - boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName); - // Return the LockoutTracker status for the specified user int getLockoutModeForUser(int sensorId, int userId); diff --git a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl index 56dba7ea1d9a..1aa6fa197066 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl @@ -24,4 +24,5 @@ import android.hardware.fingerprint.Fingerprint; */ oneway interface IFingerprintStateListener { void onStateChanged(int newState); + void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments); } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 881e0cfb58d7..74cb42db7858 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1749,12 +1749,12 @@ public class InputMethodService extends AbstractInputMethodService { if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) { return false; } - if ((mInputEditorInfo != null - && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) + if (mInputEditorInfo != null + && ((mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0 // If app window has portrait orientation, regardless of what display orientation // is, IME shouldn't use fullscreen-mode. || (mInputEditorInfo.internalImeOptions - & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) { + & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0)) { return false; } return true; diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index be21fea1d0df..1cceea30868c 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -17,6 +17,7 @@ package android.os; import android.app.Activity; +import android.app.GameManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -26,8 +27,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.AssetFileDescriptor; -import android.content.res.AssetManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -37,9 +36,6 @@ import dalvik.system.VMRuntime; import java.io.BufferedReader; import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; @@ -88,9 +84,6 @@ public class GraphicsEnvironment { private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*"; private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt"; - // ANGLE related properties. - private static final String ANGLE_RULES_FILE = "a4a_rules.json"; - private static final String ANGLE_TEMP_RULES = "debug.angle.rules"; private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID"; private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE = "android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE"; @@ -121,6 +114,7 @@ public class GraphicsEnvironment { private ClassLoader mClassLoader; private String mLibrarySearchPaths; private String mLibraryPermittedPaths; + private GameManager mGameManager; private int mAngleOptInIndex = -1; @@ -133,6 +127,8 @@ public class GraphicsEnvironment { final ApplicationInfo appInfoWithMetaData = getAppInfoWithMetadata(context, pm, packageName); + mGameManager = context.getSystemService(GameManager.class); + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers"); setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData); Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); @@ -151,6 +147,23 @@ public class GraphicsEnvironment { } /** + * 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 */ private boolean shouldUseAngle(Context context, Bundle coreSettings, @@ -164,21 +177,16 @@ public class GraphicsEnvironment { Log.v(TAG, "ANGLE Developer option for '" + packageName + "' " + "set to: '" + devOptIn + "'"); - // We only want to use ANGLE if the app is in the allowlist, or the developer has - // explicitly chosen something other than default driver. - // The allowlist will be generated by the ANGLE APK at both boot time and - // ANGLE update time. It will only include apps mentioned in the rules file. - final boolean allowed = checkAngleAllowlist(context, coreSettings, packageName); + // We only want to use ANGLE if the developer has explicitly chosen something other than + // default driver. final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE); - - if (allowed) { - Log.v(TAG, "ANGLE allowlist includes " + packageName); - } if (requested) { Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn); } - return allowed || requested; + final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName); + + return requested || gameModeEnabledAngle; } private int getVulkanVersion(PackageManager pm) { @@ -475,117 +483,6 @@ public class GraphicsEnvironment { } /** - * 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 * * @param context @@ -647,28 +544,21 @@ public class GraphicsEnvironment { if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths); - // If the user has set the developer option to something other than default, - // we need to call setupAngleRulesApk() with the package name and the developer - // option value (native/angle/other). Then later when we are actually trying to - // load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before - // and can confidently answer yes/no based on the previously set developer - // option value. - final String devOptIn = getDriverForPackage(context, bundle, packageName); - - if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) { - // We setup ANGLE with a temp rules file, so we're done here. - return true; - } - - String[] features = getAngleEglFeatures(context, bundle); - - if (setupAngleRulesApk( - anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) { - // ANGLE with rules is set up from the APK, hence return. - return true; + // We need to call setAngleInfo() with the package name and the developer option value + //(native/angle/other). Then later when we are actually trying to load a driver, + //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently + //answer yes/no based on the previously set developer option value. + final String devOptIn; + final String[] features = getAngleEglFeatures(context, bundle); + final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName); + if (gameModeEnabledAngle) { + devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE; + } else { + devOptIn = getDriverForPackage(context, bundle, packageName); } + setAngleInfo(paths, packageName, devOptIn, features); - return false; + return true; } /** @@ -956,7 +846,7 @@ public class GraphicsEnvironment { private static native void setGpuStats(String driverPackageName, String driverVersionName, long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion); private static native void setAngleInfo(String path, String appPackage, String devOptIn, - String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength); + String[] features); private static native boolean getShouldUseAngle(String packageName); private static native boolean setInjectLayersPrSetDumpable(); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ac520e8b3dec..a55484b89177 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11845,6 +11845,12 @@ public final class Settings { 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. * * Type: int (0 for false, 1 for true) @@ -13670,13 +13676,6 @@ public final class Settings { "angle_gl_driver_selection_values"; /** - * List of package names that should check ANGLE rules - * @hide - */ - @Readable - public static final String ANGLE_ALLOWLIST = "angle_allowlist"; - - /** * Lists of ANGLE EGL features for debugging. * Each list of features is separated by a comma, each feature in each list is separated by * a colon. @@ -14915,6 +14914,16 @@ public final class Settings { "power_button_long_press"; /** + * Override internal R.integer.config_longPressOnPowerDurationMs. It determines the length + * of power button press to be considered a long press in milliseconds. + * Used by PhoneWindowManager. + * @hide + */ + @Readable + public static final String POWER_BUTTON_LONG_PRESS_DURATION_MS = + "power_button_long_press_duration_ms"; + + /** * Overrides internal R.integer.config_veryLongPressOnPowerBehavior. * Allowable values detailed in frameworks/base/core/res/res/values/config.xml. * Used by PhoneWindowManager. diff --git a/core/java/android/view/ScrollCaptureResponse.java b/core/java/android/view/ScrollCaptureResponse.java index 8808827b248a..758f9ab935cf 100644 --- a/core/java/android/view/ScrollCaptureResponse.java +++ b/core/java/android/view/ScrollCaptureResponse.java @@ -53,6 +53,10 @@ public class ScrollCaptureResponse implements Parcelable { @Nullable private String mWindowTitle = null; + /** The package which owns the window. */ + @Nullable + private String mPackageName = null; + /** Carries additional logging and debugging information when enabled. */ @NonNull @DataClass.PluralOf("message") @@ -77,7 +81,7 @@ public class ScrollCaptureResponse implements Parcelable { - // Code below generated by codegen v1.0.22. + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -97,6 +101,7 @@ public class ScrollCaptureResponse implements Parcelable { @Nullable Rect windowBounds, @Nullable Rect boundsInWindow, @Nullable String windowTitle, + @Nullable String packageName, @NonNull ArrayList<String> messages) { this.mDescription = description; com.android.internal.util.AnnotationValidations.validate( @@ -105,6 +110,7 @@ public class ScrollCaptureResponse implements Parcelable { this.mWindowBounds = windowBounds; this.mBoundsInWindow = boundsInWindow; this.mWindowTitle = windowTitle; + this.mPackageName = packageName; this.mMessages = messages; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mMessages); @@ -153,6 +159,14 @@ public class ScrollCaptureResponse implements Parcelable { } /** + * 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. */ @DataClass.Generated.Member @@ -172,6 +186,7 @@ public class ScrollCaptureResponse implements Parcelable { "windowBounds = " + mWindowBounds + ", " + "boundsInWindow = " + mBoundsInWindow + ", " + "windowTitle = " + mWindowTitle + ", " + + "packageName = " + mPackageName + ", " + "messages = " + mMessages + " }"; } @@ -187,12 +202,14 @@ public class ScrollCaptureResponse implements Parcelable { if (mWindowBounds != null) flg |= 0x4; if (mBoundsInWindow != null) flg |= 0x8; if (mWindowTitle != null) flg |= 0x10; + if (mPackageName != null) flg |= 0x20; dest.writeByte(flg); dest.writeString(mDescription); if (mConnection != null) dest.writeStrongInterface(mConnection); if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags); if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags); if (mWindowTitle != null) dest.writeString(mWindowTitle); + if (mPackageName != null) dest.writeString(mPackageName); dest.writeStringList(mMessages); } @@ -213,6 +230,7 @@ public class ScrollCaptureResponse implements Parcelable { Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR); Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR); String windowTitle = (flg & 0x10) == 0 ? null : in.readString(); + String packageName = (flg & 0x20) == 0 ? null : in.readString(); ArrayList<String> messages = new ArrayList<>(); in.readStringList(messages); @@ -223,6 +241,7 @@ public class ScrollCaptureResponse implements Parcelable { this.mWindowBounds = windowBounds; this.mBoundsInWindow = boundsInWindow; this.mWindowTitle = windowTitle; + this.mPackageName = packageName; this.mMessages = messages; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mMessages); @@ -256,6 +275,7 @@ public class ScrollCaptureResponse implements Parcelable { private @Nullable Rect mWindowBounds; private @Nullable Rect mBoundsInWindow; private @Nullable String mWindowTitle; + private @Nullable String mPackageName; private @NonNull ArrayList<String> mMessages; private long mBuilderFieldsSet = 0L; @@ -319,12 +339,23 @@ public class ScrollCaptureResponse implements Parcelable { } /** + * The package name of the process the window is owned by. + */ + @DataClass.Generated.Member + public @NonNull Builder setPackageName(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mPackageName = value; + return this; + } + + /** * Carries additional logging and debugging information when enabled. */ @DataClass.Generated.Member public @NonNull Builder setMessages(@NonNull ArrayList<String> value) { checkNotUsed(); - mBuilderFieldsSet |= 0x20; + mBuilderFieldsSet |= 0x40; mMessages = value; return this; } @@ -340,7 +371,7 @@ public class ScrollCaptureResponse implements Parcelable { /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull ScrollCaptureResponse build() { checkNotUsed(); - mBuilderFieldsSet |= 0x40; // Mark builder used + mBuilderFieldsSet |= 0x80; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mDescription = ""; @@ -358,6 +389,9 @@ public class ScrollCaptureResponse implements Parcelable { mWindowTitle = null; } if ((mBuilderFieldsSet & 0x20) == 0) { + mPackageName = null; + } + if ((mBuilderFieldsSet & 0x40) == 0) { mMessages = new ArrayList<>(); } ScrollCaptureResponse o = new ScrollCaptureResponse( @@ -366,12 +400,13 @@ public class ScrollCaptureResponse implements Parcelable { mWindowBounds, mBoundsInWindow, mWindowTitle, + mPackageName, mMessages); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x40) != 0) { + if ((mBuilderFieldsSet & 0x80) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -379,10 +414,10 @@ public class ScrollCaptureResponse implements Parcelable { } @DataClass.Generated( - time = 1614833185795L, - codegenVersion = "1.0.22", + time = 1628630366187L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic boolean isConnected()\npublic void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)") + inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic boolean isConnected()\npublic void close()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3550a31f9038..985f20b5ca30 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -9493,6 +9493,7 @@ public final class ViewRootImpl implements ViewParent, ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder(); response.setWindowTitle(getTitle().toString()); + response.setPackageName(mContext.getPackageName()); StringWriter writer = new StringWriter(); IndentingPrintWriter pw = new IndentingPrintWriter(writer); diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 91fc5a56d979..fe5eb085dc5c 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -740,6 +740,16 @@ public class RemoteViews implements Parcelable, Filter { } @Override + public UserHandle getUser() { + return mContextForResources.getUser(); + } + + @Override + public int getUserId() { + return mContextForResources.getUserId(); + } + + @Override public boolean isRestricted() { // Override isRestricted and direct to resource's implementation. The isRestricted is // used for determining the risky resources loading, e.g. fonts, thus direct to context diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8c63f38494ea..7e286f042384 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -707,6 +707,10 @@ public class BatteryStatsImpl extends BatteryStats { * Mapping isolated uids to the actual owning app uid. */ final SparseIntArray mIsolatedUids = new SparseIntArray(); + /** + * Internal reference count of isolated uids. + */ + final SparseIntArray mIsolatedUidRefCounts = new SparseIntArray(); /** * The statistics we have collected organized by uids. @@ -3897,6 +3901,7 @@ public class BatteryStatsImpl extends BatteryStats { public void addIsolatedUidLocked(int isolatedUid, int appUid, long elapsedRealtimeMs, long uptimeMs) { mIsolatedUids.put(isolatedUid, appUid); + mIsolatedUidRefCounts.put(isolatedUid, 1); final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs); u.addIsolatedUid(isolatedUid); } @@ -3915,19 +3920,51 @@ public class BatteryStatsImpl extends BatteryStats { } /** - * This should only be called after the cpu times have been read. + * Isolated uid should only be removed after all wakelocks associated with the uid are stopped + * and the cpu time-in-state has been read one last time for the uid. + * * @see #scheduleRemoveIsolatedUidLocked(int, int) + * + * @return true if the isolated uid is actually removed. */ @GuardedBy("this") - public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) { + public boolean maybeRemoveIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, + long uptimeMs) { + final int refCount = mIsolatedUidRefCounts.get(isolatedUid, 0) - 1; + if (refCount > 0) { + // Isolated uid is still being tracked + mIsolatedUidRefCounts.put(isolatedUid, refCount); + return false; + } + final int idx = mIsolatedUids.indexOfKey(isolatedUid); if (idx >= 0) { final int ownerUid = mIsolatedUids.valueAt(idx); final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs); u.removeIsolatedUid(isolatedUid); mIsolatedUids.removeAt(idx); + mIsolatedUidRefCounts.delete(isolatedUid); + } else { + Slog.w(TAG, "Attempted to remove untracked isolated uid (" + isolatedUid + ")"); } mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs)); + + return true; + } + + /** + * Increment the ref count for an isolated uid. + * call #maybeRemoveIsolatedUidLocked to decrement. + */ + public void incrementIsolatedUidRefCount(int uid) { + final int refCount = mIsolatedUidRefCounts.get(uid, 0); + if (refCount <= 0) { + // Uid is not mapped or referenced + Slog.w(TAG, + "Attempted to increment ref counted of untracked isolated uid (" + uid + ")"); + return; + } + mIsolatedUidRefCounts.put(uid, refCount + 1); } public int mapUid(int uid) { @@ -4287,7 +4324,7 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName, int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) { - uid = mapUid(uid); + final int mappedUid = mapUid(uid); if (type == WAKE_TYPE_PARTIAL) { // Only care about partial wake locks, since full wake locks // will be canceled when the user puts the screen to sleep. @@ -4297,9 +4334,9 @@ public class BatteryStatsImpl extends BatteryStats { } if (mRecordAllHistory) { if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, - uid, 0)) { + mappedUid, 0)) { addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, - HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid); + HistoryItem.EVENT_WAKE_LOCK_START, historyName, mappedUid); } } if (mWakeLockNesting == 0) { @@ -4308,7 +4345,7 @@ public class BatteryStatsImpl extends BatteryStats { + Integer.toHexString(mHistoryCur.states)); mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName; - mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; + mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid; mWakeLockImportant = !unimportantForLogging; addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } else if (!mWakeLockImportant && !unimportantForLogging @@ -4318,14 +4355,19 @@ public class BatteryStatsImpl extends BatteryStats { mHistoryLastWritten.wakelockTag = null; mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName; - mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; + mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = mappedUid; addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } mWakeLockImportant = true; } mWakeLockNesting++; } - if (uid >= 0) { + if (mappedUid >= 0) { + if (mappedUid != uid) { + // Prevent the isolated uid mapping from being removed while the wakelock is + // being held. + incrementIsolatedUidRefCount(uid); + } if (mOnBatteryScreenOffTimeBase.isRunning()) { // We only update the cpu time when a wake lock is acquired if the screen is off. // If the screen is on, we don't distribute the power amongst partial wakelocks. @@ -4335,7 +4377,7 @@ public class BatteryStatsImpl extends BatteryStats { requestWakelockCpuUpdate(); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs) .noteStartWakeLocked(pid, name, type, elapsedRealtimeMs); if (wc != null) { @@ -4343,8 +4385,8 @@ public class BatteryStatsImpl extends BatteryStats { wc.getTags(), getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); } else { - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, - null, getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, + mappedUid, null, getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); } } @@ -4358,7 +4400,7 @@ public class BatteryStatsImpl extends BatteryStats { public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName, int type, long elapsedRealtimeMs, long uptimeMs) { - uid = mapUid(uid); + final int mappedUid = mapUid(uid); if (type == WAKE_TYPE_PARTIAL) { mWakeLockNesting--; if (mRecordAllHistory) { @@ -4366,9 +4408,9 @@ public class BatteryStatsImpl extends BatteryStats { historyName = name; } if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, - uid, 0)) { + mappedUid, 0)) { addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, - HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid); + HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, mappedUid); } } if (mWakeLockNesting == 0) { @@ -4380,7 +4422,7 @@ public class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } } - if (uid >= 0) { + if (mappedUid >= 0) { if (mOnBatteryScreenOffTimeBase.isRunning()) { if (DEBUG_ENERGY_CPU) { Slog.d(TAG, "Updating cpu time because of -wake_lock"); @@ -4388,17 +4430,22 @@ public class BatteryStatsImpl extends BatteryStats { requestWakelockCpuUpdate(); } - getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) + getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs) .noteStopWakeLocked(pid, name, type, elapsedRealtimeMs); if (wc != null) { FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); } else { - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, - null, getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, + mappedUid, null, getPowerManagerWakeLockLevel(type), name, FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); } + + if (mappedUid != uid) { + // Decrement the ref count for the isolated uid and delete the mapping if uneeded. + maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs); + } } } @@ -16761,6 +16808,15 @@ public class BatteryStatsImpl extends BatteryStats { pw.print("UIDs removed since the later of device start or stats reset: "); pw.println(mNumUidsRemoved); + pw.println("Currently mapped isolated uids:"); + final int numIsolatedUids = mIsolatedUids.size(); + for (int i = 0; i < numIsolatedUids; i++) { + final int isolatedUid = mIsolatedUids.keyAt(i); + final int ownerUid = mIsolatedUids.valueAt(i); + final int refCount = mIsolatedUidRefCounts.get(isolatedUid); + pw.println(" " + isolatedUid + "->" + ownerUid + " (ref count = " + refCount + ")"); + } + pw.println(); dumpConstantsLocked(pw); diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 10f14b42ae42..ed6415d749a3 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -148,7 +148,7 @@ oneway interface IStatusBar */ void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, - String opPackageName, long operationId, int multiSensorConfig); + long operationId, String opPackageName, long requestId, int multiSensorConfig); /** * Used to notify the authentication dialog that a biometric has been authenticated. */ diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index e7d6d6cf8936..b3499db94c88 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -110,7 +110,8 @@ interface IStatusBarService // Used to show the authentication dialog (Biometrics, Device Credential) void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, int multiSensorConfig); + int userId, long operationId, String opPackageName, long requestId, + int multiSensorConfig); // Used to notify the authentication dialog that a biometric has been authenticated void onBiometricAuthenticated(); diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java index 8b3c1337c0c8..7a712e50e6a8 100644 --- a/core/java/com/android/internal/util/ContrastColorUtil.java +++ b/core/java/com/android/internal/util/ContrastColorUtil.java @@ -291,10 +291,10 @@ public class ContrastColorUtil { * Finds a suitable color such that there's enough contrast. * * @param color the color to start searching from. - * @param other the color to ensure contrast against. Assumed to be lighter than {@param color} - * @param findFg if true, we assume {@param color} is a foreground, otherwise a background. + * @param other the color to ensure contrast against. Assumed to be lighter than {@code color} + * @param findFg if true, we assume {@code color} is a foreground, otherwise a background. * @param minRatio the minimum contrast ratio required. - * @return a color with the same hue as {@param color}, potentially darkened to meet the + * @return a color with the same hue as {@code color}, potentially darkened to meet the * contrast ratio. */ public static int findContrastColor(int color, int other, boolean findFg, double minRatio) { @@ -331,7 +331,7 @@ public class ContrastColorUtil { * @param color the color to start searching from. * @param backgroundColor the color to ensure contrast against. * @param minRatio the minimum contrast ratio required. - * @return the same color as {@param color} with potentially modified alpha to meet contrast + * @return the same color as {@code color} with potentially modified alpha to meet contrast */ public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) { int fg = color; @@ -361,10 +361,10 @@ public class ContrastColorUtil { * Finds a suitable color such that there's enough contrast. * * @param color the color to start searching from. - * @param other the color to ensure contrast against. Assumed to be darker than {@param color} - * @param findFg if true, we assume {@param color} is a foreground, otherwise a background. + * @param other the color to ensure contrast against. Assumed to be darker than {@code color} + * @param findFg if true, we assume {@code color} is a foreground, otherwise a background. * @param minRatio the minimum contrast ratio required. - * @return a color with the same hue as {@param color}, potentially darkened to meet the + * @return a color with the same hue as {@code color}, potentially lightened to meet the * contrast ratio. */ public static int findContrastColorAgainstDark(int color, int other, boolean findFg, @@ -393,7 +393,8 @@ public class ContrastColorUtil { low = l; } } - return findFg ? fg : bg; + hsl[2] = high; + return ColorUtilsFromCompat.HSLToColor(hsl); } public static int ensureTextContrastOnBlack(int color) { @@ -452,7 +453,7 @@ public class ContrastColorUtil { } /** - * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT} + * Resolves {@code color} to an actual color if it is {@link Notification#COLOR_DEFAULT} */ public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) { if (color == Notification.COLOR_DEFAULT) { diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java index 0c2d2a9bcf41..3191e23a9883 100644 --- a/core/java/com/android/internal/widget/NotificationActionListLayout.java +++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java @@ -53,6 +53,8 @@ public class NotificationActionListLayout extends LinearLayout { private int mEmphasizedHeight; private int mRegularHeight; @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start; + int mNumNotGoneChildren; + int mNumPriorityChildren; public NotificationActionListLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -76,15 +78,14 @@ public class NotificationActionListLayout extends LinearLayout { && ((EmphasizedNotificationButton) actionView).isPriority(); } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int N = getChildCount(); + private void countAndRebuildMeasureOrder() { + final int numChildren = getChildCount(); int textViews = 0; int otherViews = 0; - int notGoneChildren = 0; - int priorityChildren = 0; + mNumNotGoneChildren = 0; + mNumPriorityChildren = 0; - for (int i = 0; i < N; i++) { + for (int i = 0; i < numChildren; i++) { View c = getChildAt(i); if (c instanceof TextView) { textViews++; @@ -92,9 +93,9 @@ public class NotificationActionListLayout extends LinearLayout { otherViews++; } if (c.getVisibility() != GONE) { - notGoneChildren++; + mNumNotGoneChildren++; if (isPriority(c)) { - priorityChildren++; + mNumPriorityChildren++; } } } @@ -119,17 +120,20 @@ public class NotificationActionListLayout extends LinearLayout { if (needRebuild) { rebuildMeasureOrder(textViews, otherViews); } + } + private int measureAndGetUsedWidth(int widthMeasureSpec, int heightMeasureSpec, int innerWidth, + boolean collapsePriorityActions) { + final int numChildren = getChildCount(); final boolean constrained = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED; - - final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight; final int otherSize = mMeasureOrderOther.size(); int usedWidth = 0; + int maxPriorityWidth = 0; int measuredChildren = 0; int measuredPriorityChildren = 0; - for (int i = 0; i < N; i++) { + for (int i = 0; i < numChildren; i++) { // Measure shortest children first. To avoid measuring twice, we approximate by looking // at the text length. final boolean isPriority; @@ -154,12 +158,20 @@ public class NotificationActionListLayout extends LinearLayout { // measure in the order of (approx.) size, a large view can still take more than its // share if the others are small. int availableWidth = innerWidth - usedWidth; - int unmeasuredChildren = notGoneChildren - measuredChildren; + int unmeasuredChildren = mNumNotGoneChildren - measuredChildren; int maxWidthForChild = availableWidth / unmeasuredChildren; - if (isPriority) { + if (isPriority && collapsePriorityActions) { + // Collapsing the actions to just the width required to show the icon. + if (maxPriorityWidth == 0) { + maxPriorityWidth = getResources().getDimensionPixelSize( + R.dimen.notification_actions_collapsed_priority_width); + } + maxWidthForChild = maxPriorityWidth + lp.leftMargin + lp.rightMargin; + } else if (isPriority) { // Priority children get a larger maximum share of the total space: // maximum priority share = (nPriority + 1) / (MAX + 1) - int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren; + int unmeasuredPriorityChildren = mNumPriorityChildren + - measuredPriorityChildren; int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren; int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren / (Notification.MAX_ACTION_BUTTONS + 1); @@ -187,6 +199,19 @@ public class NotificationActionListLayout extends LinearLayout { } else { mExtraStartPadding = 0; } + return usedWidth; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + countAndRebuildMeasureOrder(); + final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight; + int usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth, + false /* collapsePriorityButtons */); + if (mNumPriorityChildren != 0 && usedWidth >= innerWidth) { + usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth, + true /* collapsePriorityButtons */); + } mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding; setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec), diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index b40491a49b14..f44e829d49d7 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -50,8 +50,7 @@ void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName, } void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, - jstring devOptIn, jobjectArray featuresObj, jobject rulesFd, - jlong rulesOffset, jlong rulesLength) { + jstring devOptIn, jobjectArray featuresObj) { ScopedUtfChars pathChars(env, path); ScopedUtfChars appNameChars(env, appName); ScopedUtfChars devOptInChars(env, devOptIn); @@ -74,11 +73,8 @@ void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appNa } } - int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd); - android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(), - devOptInChars.c_str(), features, - rulesFd_native, rulesOffset, rulesLength); + devOptInChars.c_str(), features); } bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) { @@ -124,8 +120,7 @@ const JNINativeMethod g_methods[] = { {"setInjectLayersPrSetDumpable", "()Z", reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)}, {"setAngleInfo", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/io/" - "FileDescriptor;JJ)V", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V", reinterpret_cast<void*>(setAngleInfo_native)}, {"getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native)}, diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index c3d159659622..83e26f66fd62 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -771,6 +771,8 @@ message GlobalSettingsProto { optional SettingProto power_manager_constants = 93; reserved 94; // Used to be priv_app_oob_enabled + optional SettingProto power_button_long_press_duration_ms = 154 [ (android.privacy).dest = DEST_AUTOMATIC ]; + message PrepaidSetup { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -970,6 +972,7 @@ message GlobalSettingsProto { optional SettingProto usb_mass_storage_enabled = 127 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto use_google_mail = 128 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto use_open_wifi_package = 129 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto uwb_enabled = 155 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto vt_ims_enabled = 130 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto wait_for_debugger = 131 [ (android.privacy).dest = DEST_AUTOMATIC ]; @@ -1063,5 +1066,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 154; + // Next tag = 156; } diff --git a/core/res/res/drawable/btn_notification_emphasized.xml b/core/res/res/drawable/btn_notification_emphasized.xml index 29c51f2a33c9..7c09fb889c48 100644 --- a/core/res/res/drawable/btn_notification_emphasized.xml +++ b/core/res/res/drawable/btn_notification_emphasized.xml @@ -24,9 +24,9 @@ android:insetBottom="@dimen/button_inset_vertical_material"> <shape android:shape="rectangle"> <corners android:radius="@dimen/notification_action_button_radius" /> - <padding android:left="12dp" + <padding android:left="16dp" android:top="@dimen/button_padding_vertical_material" - android:right="12dp" + android:right="16dp" android:bottom="@dimen/button_padding_vertical_material" /> <solid android:color="@color/white" /> </shape> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 6946b3c07652..4541366c31cb 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gebruik jou vingerafdruk of skermslot om voort te gaan"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Iets is fout. Probeer weer."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdrukikoon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Gesigslot"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Kwessie met Gesigslot"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik jou gesig of skermslot om voort te gaan"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Iets is fout. Probeer weer."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Gesig-ikoon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lees sinkroniseer-instellings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Laat die program toe om die sinkroniseringinstellings van \'n rekening te lees. Byvoorbeeld, dit kan bepaal of die People-program met \'n rekening gesinkroniseer is."</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 9ab2f1939c84..4da99e27ebf7 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ለመቀጠል የጣት አሻራዎን ወይም የማያ ገጽ ቁልፍዎን ይጠቀሙ"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"የጣት አሻራ አዶ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"በመልክ መክፈት"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ከመልክ መክፈት ጋር በተያያዘ ችግር"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ለመቀጠል መልክዎን ወይም የማያ ገጽዎን መቆለፊያ ይጠቀሙ"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string> <string name="face_icon_content_description" msgid="465030547475916280">"የፊት አዶ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"የሥምሪያ ቅንብሮች አንብብ"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"መተግበሪያው የአንድ መለያ የማመሳሰል ቅንብሮችን እንዲያነብ ይፈቅድለታል። ለምሳሌ ይህ የሰዎች መተግበሪያ ከመለያ ጋር መመሳሰሉን አለመመሳሰሉን ሊወስን ይችላል።"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 14221dc5fb6b..3746f3e14b42 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -621,6 +621,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"استخدام بصمة الإصبع أو قفل الشاشة للمتابعة"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"حدث خطأ، يُرجى إعادة المحاولة."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"رمز بصمة الإصبع"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"فتح الجهاز بالتعرف على الوجه"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"مشكلة متعلّقة بميزة \"فتح الجهاز بالتعرف على الوجه\""</string> @@ -673,6 +674,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"استخدام ميزة \"فتح القفل بالوجه\" أو ميزة \"قفل الشاشة\" للمتابعة"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"حدث خطأ، يُرجى إعادة المحاولة."</string> <string name="face_icon_content_description" msgid="465030547475916280">"رمز الوجه"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"قراءة إعدادات المزامنة"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 96403247a7f4..5b9ef9bfff77 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -242,7 +242,7 @@ <string name="global_actions" product="tablet" msgid="4412132498517933867">"টে\'বলেটৰ বিকল্পসমূহ"</string> <string name="global_actions" product="tv" msgid="3871763739487450369">"Android TVৰ বিকল্পসমূহ"</string> <string name="global_actions" product="default" msgid="6410072189971495460">"ফ\'নৰ বিকল্পসমূহ"</string> - <string name="global_action_lock" msgid="6949357274257655383">"স্ক্ৰীণ ল\'ক"</string> + <string name="global_action_lock" msgid="6949357274257655383">"স্ক্ৰীন লক"</string> <string name="global_action_power_off" msgid="4404936470711393203">"পাৱাৰ অফ"</string> <string name="global_action_power_options" msgid="1185286119330160073">"পাৱাৰ"</string> <string name="global_action_restart" msgid="4678451019561687074">"ৰিষ্টাৰ্ট কৰক"</string> @@ -329,7 +329,7 @@ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ৱিণ্ড’ সমল বিচাৰি উলিওৱাৰ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"আপুনি চাই থকা ৱিণ্ড’খনৰ সমল পৰীক্ষা কৰাৰ।"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰাৰ"</string> - <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"আঙুলিৰে টিপা বস্তুসমূহ ডাঙৰকৈ কৈ শুনোৱা হ’ব আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ দি স্ক্ৰীণ অন্বেষণ কৰিব পাৰিব।"</string> + <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"আঙুলিৰে টিপা বস্তুসমূহ ডাঙৰকৈ কৈ শুনোৱা হ’ব আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ দি স্ক্ৰীন অন্বেষণ কৰিব পাৰিব।"</string> <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"আপুনি লিখা পাঠ নিৰীক্ষণ কৰাৰ"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"ক্ৰেডিট কাৰ্ডৰ নম্বৰ আৰু পাছৱৰ্ডৰ দৰে ব্যক্তিগত ডেটা ইয়াত অন্তৰ্ভুক্ত।"</string> <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"ডিছপ্লে’ৰ বিবৰ্ধন নিয়ন্ত্ৰণ কৰাৰ"</string> @@ -387,7 +387,7 @@ <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"অন্য এপবোৰ বন্ধ কৰক"</string> <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"এপটোক অন্য এপসমূহৰ নেপথ্যৰ প্ৰক্ৰিয়াসমূহ শেষ কৰিবলৈ অনুমতি দিয়ে৷ এই কার্যৰ বাবে অন্য এপসমূহ চলাটো বন্ধ হ\'ব পাৰে৷"</string> <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"এই এপটো অইন এপৰ ওপৰত প্ৰদৰ্শিত হ\'ব পাৰে"</string> - <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"এই এপটো অইন এপৰ ওপৰত বা স্ক্ৰীণৰ অইন অংশত প্ৰদৰ্শিত হ\'ব পাৰে। এই কাৰ্যই এপসমূহৰ স্বাভাৱিক কাৰ্যকলাপত ব্যাঘাত জন্মাব পাৰে আৰু অইন এপসমূহক স্ক্ৰীণত কেনেকৈ দেখা পোৱা যায় সেইটো সলনি কৰিব পাৰে।"</string> + <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"এই এপ্টো অন্য এপৰ ওপৰত বা স্ক্ৰীনৰ অন্য অংশত প্ৰদৰ্শিত হ\'ব পাৰে। এই কাৰ্যই এপৰ স্বাভাৱিক ব্যৱহাৰত ব্যাঘাত জন্মাব পাৰে আৰু অন্য এপ্সমূহক স্ক্ৰীনত কেনেকৈ দেখা পোৱা যায় সেইটো সলনি কৰিব পাৰে।"</string> <string name="permlab_runInBackground" msgid="541863968571682785">"নেপথ্যত চলিব পাৰে"</string> <string name="permdesc_runInBackground" msgid="4344539472115495141">"এই এপটো নেপথ্যত চলিব পাৰে। ইয়াৰ ফলত বেটাৰি সোনকালে শেষ হ\'ব পাৰে।"</string> <string name="permlab_useDataInBackground" msgid="783415807623038947">"নেপথ্যত ডেটা ব্যৱহাৰ কৰিব পাৰে"</string> @@ -545,10 +545,10 @@ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"এপ্টোক অগ্ৰাধিকাৰ দিয়া nfc পৰিশোধ সেৱাৰ পঞ্জীকৃত সহায়কসমূহ আৰু পৰিশোধ কৰিব লগা লক্ষ্যস্থান দৰে তথ্য পাবলৈ অনুমতি দিয়ে।"</string> <string name="permlab_nfc" msgid="1904455246837674977">"নিয়েৰ ফিল্ড কমিউনিকেশ্বন নিয়ন্ত্ৰণ কৰক"</string> <string name="permdesc_nfc" msgid="8352737680695296741">"এপটোক নিয়েৰ ফিল্ড কমিউনিকেশ্বন (NFC) টেগ, কাৰ্ড আৰু ৰিডাৰসমূহৰ সৈতে যোগাযোগ কৰিবলৈ অনুমতি দিয়ে।"</string> - <string name="permlab_disableKeyguard" msgid="3605253559020928505">"আপোনাৰ স্ক্ৰীণ ল\'ক অক্ষম কৰক"</string> + <string name="permlab_disableKeyguard" msgid="3605253559020928505">"আপোনাৰ স্ক্ৰীন লক অক্ষম কৰক"</string> <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"এপটোক কী ল\'ক আৰু জড়িত হোৱা যিকোনো পাছৱৰ্ডৰ সুৰক্ষা অক্ষম কৰিব দিয়ে৷ উদাহৰণস্বৰূপে, কোনো অন্তৰ্গামী ফ\'ন কল উঠোৱাৰ সময়ত ফ\'নটোৱে কী-লকটো অক্ষম কৰে, তাৰ পিছত কল শেষ হ\'লেই কী লকটো পুনৰ সক্ষম কৰে৷"</string> <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"স্ক্ৰীণ লকৰ জটিলতাৰ অনুৰোধ"</string> - <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"এপটোক স্ক্ৰীণ লকৰ জটিলতাৰ স্তৰ (উচ্চ, মধ্যম, নিম্ন বা একেবাৰে নাই) শিকিবলৈ অনুমতি দিয়ে ই স্ক্ৰীণ লকৰ সম্ভাব্য দৈৰ্ঘ্য বা স্ক্ৰীণ লকৰ প্ৰকাৰ দৰ্শায়। লগতে এপটোৱে ব্যৱহাৰকাৰীক স্ক্ৰীণ লকটো এটা নিৰ্দিষ্ট স্তৰলৈ আপডে’ট কৰিবলৈ পৰামৰ্শ দিব পাৰে যিটো ব্যৱহাৰকাৰীয়ে অৱজ্ঞা কৰি পৰৱর্তী পৃষ্ঠালৈ যাব পাৰে। মনত ৰাখিব যে স্ক্ৰীণ লকটো সাধাৰণ পাঠ হিচাপে সঞ্চয় কৰা নহয় সেয়ে এপ্টোৱে সঠিক পাছৱৰ্ডটো জানিব নোৱাৰে।"</string> + <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"এপ্টোক স্ক্ৰীন লকৰ জটিলতাৰ স্তৰ (উচ্চ, মধ্যম, নিম্ন বা একেবাৰে নাই)ৰ বিষয়ে জানিবলৈ অনুমতি দিয়ে, যিয়ে স্ক্ৰীন লকৰ সম্ভাব্য দৈৰ্ঘ্য বা স্ক্ৰীন লকৰ প্ৰকাৰ দৰ্শায়। লগতে এপ্টোৱে ব্যৱহাৰকাৰীক স্ক্ৰীন লকটো এটা নিৰ্দিষ্ট স্তৰলৈ আপডে’ট কৰিবলৈ পৰামৰ্শ দিব পাৰে যিটো ব্যৱহাৰকাৰীয়ে অৱজ্ঞা কৰি পৰৱর্তী পৃষ্ঠালৈ যাব পাৰে। মনত ৰাখিব যে স্ক্ৰীন লকটো সাধাৰণ পাঠ হিচাপে ষ্ট\'ৰ কৰা নহয়; সেয়েহে, এপ্টোৱে সঠিক পাছৱৰ্ডটো জানিব নোৱাৰে।"</string> <string name="permlab_useBiometric" msgid="6314741124749633786">"বায়োমেট্ৰিক হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰক"</string> <string name="permdesc_useBiometric" msgid="7502858732677143410">"বিশ্বাসযোগ্য়তা প্ৰমাণীকৰণৰ বাবে এপক বায়োমেট্ৰিক হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string> <string name="permlab_manageFingerprint" msgid="7432667156322821178">"ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ পৰিচালনা কৰিব পাৰে"</string> @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ফিংগাৰপ্ৰিণ্ট আইকন"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেচ আনলক"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ফেচ আনলক ব্যৱহাৰ কৰোঁতে সমস্যা হৈছে"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"অব্যাহত ৰাখিবলৈ আপোনাৰ মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string> <string name="face_icon_content_description" msgid="465030547475916280">"মুখমণ্ডলৰ আইকন"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ছিংকৰ ছেটিংসমূহ পঢ়ক"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ কোনো একাউণ্টত ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string> @@ -680,8 +682,8 @@ <string name="permdesc_register_call_provider" msgid="4201429251459068613">"এপটোক নতুন টেলিকম সংযোগ পঞ্জীয়ন কৰিবলৈ অনুমতি দিয়ে।"</string> <string name="permlab_connection_manager" msgid="3179365584691166915">"টেলিকম সংযোগ পৰিচালনা কৰা"</string> <string name="permdesc_connection_manager" msgid="1426093604238937733">"এপটোক টেলিকম সংযোগ পৰিচালনা কৰিবলৈ অনুমতি দিয়ে।"</string> - <string name="permlab_bind_incall_service" msgid="5990625112603493016">"ইন-কল স্ক্ৰীণৰ সৈতে সংযোগ স্থাপন"</string> - <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"ব্যৱহাৰকাৰীয়ে কেতিয়া আৰু কেনেদৰে ইন-কল-স্ক্ৰীণ চাব, তাক নিয়ন্ত্ৰণ কৰিবলৈ এপক অনুমতি দিয়ে।"</string> + <string name="permlab_bind_incall_service" msgid="5990625112603493016">"ইন-কল স্ক্ৰীনৰ সৈতে সংযোগ স্থাপন"</string> + <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"ব্যৱহাৰকাৰীগৰাকীয়ে কেতিয়া আৰু কেনেদৰে ইন-কল-স্ক্ৰীন চায় সেয়া নিয়ন্ত্ৰণ কৰিবলৈ এপ্টোক অনুমতি দিয়ে।"</string> <string name="permlab_bind_connection_service" msgid="5409268245525024736">"টেলিফ\'নী সেৱাসমূহৰ সৈতে সংযোগ স্থাপন"</string> <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"কল কৰিবলৈ/লাভ কৰিবলৈ টেলিফ\'নী সেৱাসমূহৰ সৈতে এপক সংযোগ স্থাপনৰ বাবে অনুমতি দিয়ে।"</string> <string name="permlab_control_incall_experience" msgid="6436863486094352987">"ইন-কল ব্যৱহাৰকাৰীৰ অভিজ্ঞতা প্ৰদান কৰা"</string> @@ -705,7 +707,7 @@ <string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"নেটৱৰ্ক অৱস্থাসমূহৰ ওপৰত নিৰীক্ষণৰ বাবে শুনিব পাৰে"</string> <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"এটা এপ্লিকেশ্বনক নেটৱৰ্ক অৱস্থাসমূহত নিৰীক্ষণৰ বাবে শুনিবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string> <string name="permlab_setInputCalibration" msgid="932069700285223434">"ইনপুট ডিভাইচ কেলিব্ৰেশ্বন সলনি কৰিব পাৰে"</string> - <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"টাচ্চ স্ক্ৰীণৰ কেলিব্ৰেশ্বন পেৰামিটাৰ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string> + <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"টাচ্চ স্ক্ৰীনৰ কেলিব্ৰেশ্বন পেৰামিটাৰ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে কেতিয়াও প্ৰয়োজন হোৱা উচিত নহয়।"</string> <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM প্ৰমাণপত্ৰসমূহলৈ প্ৰৱেশ"</string> <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"এটা এপ্লিকেশ্বনক DRM প্ৰমাণপত্ৰ গোটাবলৈ আৰু ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string> <string name="permlab_handoverStatus" msgid="7620438488137057281">"Android বীম স্থানান্তৰণৰ স্থিতি লাভ কৰিব পাৰে"</string> @@ -723,18 +725,18 @@ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"এটা উচ্চ ছেম্পলিঙৰ হাৰত ছেন্সৰৰ ডেটা এক্সেছ কৰে"</string> <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"এপ্টোক ২০০ হাৰ্টজতকৈ অধিক হাৰত ছেন্সৰৰ ডেটাৰ নমুনা ল’বলৈ অনুমতি দিয়ে"</string> <string name="policylab_limitPassword" msgid="4851829918814422199">"পাছৱর্ডৰ নিয়ম ছেট কৰক"</string> - <string name="policydesc_limitPassword" msgid="4105491021115793793">"স্ক্ৰীণ লক পাছৱৰ্ড আৰু পিনৰ দৈর্ঘ্য আৰু কি কি আখৰ ব্যৱহাৰ কৰিব পাৰে তাক নিয়ন্ত্ৰণ কৰক।"</string> - <string name="policylab_watchLogin" msgid="7599669460083719504">"স্ক্ৰীণ আনলক কৰা প্ৰয়াসবোৰ পৰ্যবেক্ষণ কৰিব পাৰে"</string> + <string name="policydesc_limitPassword" msgid="4105491021115793793">"স্ক্ৰীন লক পাছৱৰ্ড আৰু পিনত অনুমোদিত দৈৰ্ঘ্য আৰু বৰ্ণবোৰ নিয়ন্ত্ৰণ কৰক।।"</string> + <string name="policylab_watchLogin" msgid="7599669460083719504">"স্ক্ৰীন আনলক কৰা প্ৰয়াসবোৰ নিৰীক্ষণ কৰক"</string> <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে টে\'বলেটটো লক কৰক বা টে\'বলেটটোৰ সকলো ডেটা মোহাৰক।"</string> <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"স্ক্ৰীণ আনলক কৰোঁতে দিয়া ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড দিয়া হয় তেন্তে Android TV ডিভাইচটো লক কৰক অথবা আপোনাৰ Android TV ডিভাইচৰ সকলো ডেটা মচক।"</string> <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে ফ\'নটো লক কৰক বা ফ\'নটোৰ সকলো ডেটা মোহাৰক।"</string> - <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড দিয়া হয় তেন্তে টে\'বলেটটো লক কৰক বা এই ব্যৱহাৰকাৰীৰ সকলো ডেটা মচক।"</string> - <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"স্ক্ৰীণখন আনলক কৰোঁতে টাইপ কৰা ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড টাইপ কৰা হয় তেন্তে Android TV ডিভাইচটো লক কৰক অথবা এই ব্যৱহাৰকাৰীৰ সকলো ডেটা মচক।"</string> - <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"স্ক্ৰীণ আনলক কৰোতে দিয়া অশুদ্ধ পাছৱৰ্ডৰ হিচাপ নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড দিয়া হয় তেন্তে ফ\'নটো লক কৰক বা এই ব্যৱহাৰকাৰীৰ সকলো ডেটা মচক।"</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"স্ক্ৰীণ লক সলনি কৰক"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"স্ক্ৰীণ লক সলনি কৰক।"</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"স্ক্ৰীণখন লক কৰক"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"স্ক্ৰীণ কেনেকৈ আৰু কেতিয়া ল\'ক হ\'ব লাগে সেয়া নিয়ন্ত্ৰণ কৰক।"</string> + <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"স্ক্ৰীন আনলক কৰোঁতে টাইপ কৰা অশুদ্ধ পাছৱৰ্ডৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে টেবলেটটো লক কৰক বা এই ব্যৱহাৰকাৰীৰ আটাইখিনি ডেটা মচক।"</string> + <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"স্ক্ৰীনখন আনলক কৰোঁতে টাইপ কৰা ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে Android TV ডিভাইচটো লক কৰক অথবা এই ব্যৱহাৰকাৰীৰ আটাইখিনি ডেটা মচক।"</string> + <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"স্ক্ৰীনখন আনলক কৰোঁতে টাইপ কৰা ভুল পাছৱৰ্ডবোৰৰ সংখ্যা নিৰীক্ষণ কৰক আৰু যদিহে অত্যধিকবাৰ ভুল পাছৱৰ্ড টাইপ কৰা হয়, তেন্তে ফ\'নটো লক কৰক অথবা এই ব্যৱহাৰকাৰীৰ আটাইখিনি ডেটা মচক।"</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"স্ক্ৰীন লক সলনি কৰক"</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"স্ক্ৰীন লক সলনি কৰক।"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"স্ক্ৰীনখন লক কৰক"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"স্ক্ৰীন কেনেকৈ আৰু কেতিয়া লক হয় সেয়া নিয়ন্ত্ৰণ কৰক।"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"সকলো ডেটা মচক"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"সতৰ্কবাণী প্ৰেৰণ নকৰাকৈয়ে ফেক্টৰী ডেটা ৰিছেট কৰি টেবলেটৰ ডেটা মচক।"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"কোনো সতর্কবার্তা নপঠিওৱাকৈ ফেক্টৰী ডেটা ৰিছেট কৰি আপোনাৰ Android TV ডিভাইচৰ ডেটা মচক।"</string> @@ -745,13 +747,13 @@ <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"এই ফ\'নটোত থকা এই ব্যৱহাৰকাৰীৰ তথ্য কোনো সর্তকবাণী নিদিয়াকৈ মচি পেলাওক।"</string> <string name="policylab_setGlobalProxy" msgid="215332221188670221">"ডিভাইচৰ বাবে গ্ল\'বেল প্ৰক্সী ছেট কৰক"</string> <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"নীতি সক্ষম কৰি থোৱা অৱস্থাত ব্য়ৱহাৰ কৰিবৰ বাবে ডিভাইচৰ বাবে গ্ল\'বেল প্ৰক্সী ছেট কৰক। কেৱল ডিভাইচৰ গৰাকীয়েহে গ্ল\'বেল প্ৰক্সী ছেট কৰিব পাৰে।"</string> - <string name="policylab_expirePassword" msgid="6015404400532459169">"স্ক্ৰীণ লক পাছৱৰ্ডৰ ম্যাদ ওকলাৰ দিন ছেট কৰক"</string> - <string name="policydesc_expirePassword" msgid="9136524319325960675">"স্ক্ৰীণ লকৰ পাছৱৰ্ড, পিন বা আর্হি কিমান ঘনাই সলনি কৰিব লাগিব তাক সলনি কৰক।"</string> + <string name="policylab_expirePassword" msgid="6015404400532459169">"স্ক্ৰীন লক পাছৱৰ্ডৰ ম্যাদ ওকলাৰ দিন ছেট কৰক"</string> + <string name="policydesc_expirePassword" msgid="9136524319325960675">"স্ক্ৰীন লকৰ পাছৱৰ্ড, পিন বা আর্হি কিমান ঘনাই সলনি কৰিব লাগিব তাক সলনি কৰক।"</string> <string name="policylab_encryptedStorage" msgid="9012936958126670110">"সঞ্চয়াগাৰৰ এনক্ৰিপশ্বন ছেট কৰক"</string> <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"সঞ্চয় কৰি ৰখা ডেটাক এনক্ৰিপ্ট কৰাৰ প্ৰয়োজন।"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"কেমেৰাবোৰ অক্ষম কৰক"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"সকলো ডিভাইচৰ কেমেৰাবোৰ ব্যৱহাৰ কৰাত বাধা দিয়ক।"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"স্ক্ৰীণ লকৰ কিছুমান সুবিধা অক্ষম কৰক"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"স্ক্ৰীন লকৰ কিছুমান সুবিধা অক্ষম কৰক"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"স্ক্ৰীণ লকৰ কিছুমান সুবিধা ব্যৱহাৰ হোৱাত বাধা দিয়ক।"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"ঘৰ"</item> @@ -878,7 +880,7 @@ <string name="keyguard_label_text" msgid="3841953694564168384">"আনলক কৰিবলৈ মেনু টিপাৰ পিছত ০ টিপক।"</string> <string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"জৰুৰীকালীন নম্বৰ"</string> <string name="lockscreen_carrier_default" msgid="6192313772955399160">"কোনো সেৱা নাই"</string> - <string name="lockscreen_screen_locked" msgid="7364905540516041817">"স্ক্ৰীণ লক কৰা হ’ল।"</string> + <string name="lockscreen_screen_locked" msgid="7364905540516041817">"স্ক্ৰীন লক কৰা হ’ল।"</string> <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক কৰিবলৈ বা জৰুৰীকালীন কল কৰিবলৈ মেনু টিপক।"</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক কৰিবলৈ মেনু টিপক।"</string> <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক কৰিবলৈ আর্হি আঁকক"</string> @@ -1391,7 +1393,7 @@ <string name="share_remote_bugreport_action" msgid="7630880678785123682">"শ্বেয়াৰ কৰক"</string> <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"প্ৰত্যাখ্যান কৰক"</string> <string name="select_input_method" msgid="3971267998568587025">"ইনপুট পদ্ধতি বাছনি কৰক"</string> - <string name="show_ime" msgid="6406112007347443383">"কায়িক কীব’ৰ্ড সক্ৰিয় হৈ থাকোঁতে ইয়াক স্ক্ৰীণত ৰাখিব"</string> + <string name="show_ime" msgid="6406112007347443383">"কায়িক কীব’ৰ্ড সক্ৰিয় হৈ থাকোঁতে ইয়াক স্ক্ৰীনত ৰাখক"</string> <string name="hardware" msgid="1800597768237606953">"ভাৰ্শ্বুৱল কীব\'ৰ্ড দেখুৱাওক"</string> <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"কায়িক কীব’ৰ্ড কনফিগাৰ কৰক"</string> <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ভাষা আৰু চানেকি বাছনি কৰিবলৈ ইয়াত টিপক"</string> @@ -1629,7 +1631,7 @@ <string name="wireless_display_route_description" msgid="8297563323032966831">"ৱায়াৰলেচ ডিছপ্লে’"</string> <string name="media_route_button_content_description" msgid="2299223698196869956">"কাষ্ট"</string> <string name="media_route_chooser_title" msgid="6646594924991269208">"ডিভাইচৰ লগত সংযোগ কৰক"</string> - <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"ডিভাইচত স্ক্ৰীণ কাষ্ট কৰক"</string> + <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"ডিভাইচত স্ক্ৰীন কাষ্ট কৰক"</string> <string name="media_route_chooser_searching" msgid="6119673534251329535">"ডিভাইচৰ সন্ধান কৰক…"</string> <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"ছেটিংসমূহ"</string> <string name="media_route_controller_disconnect" msgid="7362617572732576959">"বিচ্ছিন্ন কৰক"</string> @@ -1638,8 +1640,8 @@ <string name="media_route_status_available" msgid="1477537663492007608">"উপলব্ধ"</string> <string name="media_route_status_not_available" msgid="480912417977515261">"উপলব্ধ নহয়"</string> <string name="media_route_status_in_use" msgid="6684112905244944724">"ব্যৱহাৰ হৈ আছে"</string> - <string name="display_manager_built_in_display_name" msgid="1015775198829722440">"অন্তৰ্নিমিত স্ক্ৰীণ"</string> - <string name="display_manager_hdmi_display_name" msgid="1022758026251534975">"HDMI স্ক্ৰীণ"</string> + <string name="display_manager_built_in_display_name" msgid="1015775198829722440">"বিল্ট-ইন স্ক্ৰীন"</string> + <string name="display_manager_hdmi_display_name" msgid="1022758026251534975">"HDMI স্ক্ৰীন"</string> <string name="display_manager_overlay_display_name" msgid="5306088205181005861">"অ\'ভাৰলে\' #<xliff:g id="ID">%1$d</xliff:g>"</string> <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", সুৰক্ষিত"</string> @@ -2088,7 +2090,7 @@ <string name="notification_app_name_settings" msgid="9088548800899952531">"ছেটিংসমূহ"</string> <string name="notification_appops_camera_active" msgid="8177643089272352083">"কেমেৰা"</string> <string name="notification_appops_microphone_active" msgid="581333393214739332">"মাইক্ৰ\'ফ\'ন"</string> - <string name="notification_appops_overlay_active" msgid="5571732753262836481">"স্ক্ৰীণত অইন এপৰ ওপৰত দেখুৱাওক"</string> + <string name="notification_appops_overlay_active" msgid="5571732753262836481">"আপোনাৰ স্ক্ৰীনত থকা অন্য় এপৰ ওপৰত প্ৰদৰ্শিত হৈ আছে"</string> <string name="notification_feedback_indicator" msgid="663476517711323016">"মতামত দিয়ক"</string> <string name="notification_feedback_indicator_alerted" msgid="6552871804121942099">"এই জাননীটোৰ গুৰুত্ব ডিফ’ল্টলৈ বৃদ্ধি কৰা হৈছে। মতামত দিবলৈ টিপক।"</string> <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"এই জাননীটোৰ গুৰুত্ব নীৰৱলৈ হ্ৰাস কৰা হৈছে। মতামত দিবলৈ টিপক।"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index bab05ad489b3..7d415342d1b8 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Davam etmək üçün barmaq izi və ya ekran kilidinizdən istifadə edin"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Xəta oldu. Yenə cəhd edin."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmaq izi ikonası"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Üz ilə kiliddən çıxarma"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Üz ilə kiliddən çıxarma problemi"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davam etmək üçün üz və ya ekran kilidinizdən istifadə edin"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Xəta oldu. Yenə cəhd edin."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Üz işarəsi"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"sinx ayarlarını oxu"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tətbiqə hesablar üçün sinxronizasiya nizamlarını oxuma icazəsi verir. Məsələn, bu Şəxslər tətbiqinin sinxronizə olunub-olunmadığını təyin edə bilər."</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 4179ab03dac3..7f7d62e8ce7d 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -612,6 +612,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Koristite otisak prsta ili zaključavanje ekrana da biste nastavili"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Došlo je do problema. Probajte ponovo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem sa otključavanje licem"</string> @@ -664,6 +665,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da biste nastavili"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Došlo je do problema. Probajte ponovo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje podešavanja sinhronizacije"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Dozvoljava aplikaciji da čita podešavanja sinhronizacije za nalog. Na primer, ovako može da se utvrdi da li je aplikacija Ljudi sinhronizovana sa nalogom."</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index f0c8f88609f4..49938844104a 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Каб працягнуць, скарыстайце адбітак пальца ці сродак разблакіроўкі экрана"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Нешта пайшло не так. Паўтарыце спробу."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок адбіткаў пальцаў"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Распазнаванне твару"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Праблема з распазнаваннем твару"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Каб працягнуць, скарыстайце распазнаванне твару ці сродак разблакіроўкі экрана"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Нешта пайшло не так. Паўтарыце спробу."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Значок твару"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"чытаць параметры сінхранізацыі"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дазваляе прыкладанням чытаць параметры сінхранізацыі для ўліковага запісу. Напрыклад, яны могуць вызначыць, цi сiнхранiзавана з улiковым запiсам прыкладанне \"Кантакты\"."</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 40807e5650fa..fb9c88654981 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Използвайте отпечатъка си или опцията за заключване на екрана, за да продължите"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Нещо се обърка. Опитайте отново."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатък"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Отключване с лице"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем с отключването с лице"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Използвайте лицето си или опцията за заключване на екрана, за да продължите"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Нещо се обърка. Опитайте отново."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Икона на лице"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"четене на настройките за синхронизиране"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Разрешава на приложението да чете настройките за синхронизиране на профил. Например това може да определи дали приложението Хора е синхронизирано с даден профил."</string> @@ -861,7 +863,7 @@ <string name="relationTypeReferredBy" msgid="5285082289602849400">"Препоръчан/а от"</string> <string name="relationTypeRelative" msgid="3396498519818009134">"Роднина"</string> <string name="relationTypeSister" msgid="3721676005094140671">"Сестра"</string> - <string name="relationTypeSpouse" msgid="6916682664436031703">"Съпруг/а"</string> + <string name="relationTypeSpouse" msgid="6916682664436031703">"Съпруг(а)"</string> <string name="sipAddressTypeCustom" msgid="6283889809842649336">"Персонализиран"</string> <string name="sipAddressTypeHome" msgid="5918441930656878367">"Домашен"</string> <string name="sipAddressTypeWork" msgid="7873967986701216770">"Служебен"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 2f68cdab4a03..5543d724becc 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"চালিয়ে যেতে আপনার আঙুলের ছাপ বা স্ক্রিন লক ব্য়বহার করুন"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"কোনও সমস্যা হয়েছে। আবার করে দেখুন।"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেস আনলক"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"\'ফেস আনলক\' ফিচার ব্যবহার করার ক্ষেত্রে হওয়া সমস্যা"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"চালিয়ে যেতে আপনার ফেস বা স্ক্রিন লক ব্যবহার করুন"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"কোনও সমস্যা হয়েছে। আবার করে দেখুন।"</string> <string name="face_icon_content_description" msgid="465030547475916280">"ফেস আইকন"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"সিঙ্ক সেটিংস পড়ে"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"অ্যাপ্লিকেশানটিকে একটি অ্যাকাউন্টের জন্য সিঙ্ক সেটিংস পড়ার অনুমতি দেয়৷ উদাহরণস্বরূপ, \'পিপল\' অ্যাপ্লিকেশানটি কোনো অ্যাকাউন্টের সাথে সিঙ্ক করা আছে কিনা তা নির্ধারণ করতে পারে৷"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 3ebb7ccc8471..1e574bddc045 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -612,6 +612,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Koristite otisak prsta ili zaključavanje ekrana da nastavite"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Nešto nije uredu. Pokušajte ponovo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona za otisak prsta"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem s otključavanjem licem"</string> @@ -664,6 +665,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da nastavite"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Nešto nije uredu. Pokušajte ponovo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje postavki za sinhroniziranje"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Omogućava aplikaciji čitanje postavki sinhroniziranja za račun. Naprimjer, ovim se može utvrditi da li je aplikacija People sinhronizirana sa računom."</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 880ad1804498..527615e1f168 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilitza l\'empremta digital o el bloqueig de pantalla per continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"S\'ha produït un error. Torna-ho a provar."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona d\'empremta digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueig facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema amb Desbloqueig facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilitza la cara o el bloqueig de pantalla per continuar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"S\'ha produït un error. Torna-ho a provar."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Icona facial"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"llegir la configuració de sincronització"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Contactes estigui sincronitzada amb un compte."</string> @@ -907,7 +909,7 @@ <string name="emergency_calls_only" msgid="3057351206678279851">"Només trucades d\'emergència"</string> <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Xarxa bloquejada"</string> <string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"La targeta SIM està bloquejada pel PUK."</string> - <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta la guia de l\'usuari o posa\'t en contacte amb el servei d\'atenció al client."</string> + <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta la guia d\'usuari o posa\'t en contacte amb el servei d\'atenció al client."</string> <string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"La targeta SIM està bloquejada."</string> <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"S\'està desbloquejant la targeta SIM..."</string> <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a8ae213b6180..3469a6def770 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Pokračujte ověřením pomocí otisku prstu nebo zámku obrazovky"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Došlo k chybě. Zkuste to znovu."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otisku prstů"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odemknutí obličejem"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problém s odemykáním obličejem"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte ověřením pomocí obličeje nebo zámku obrazovky"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Došlo k chybě. Zkuste to znovu."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona obličeje"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čtení nastavení synchronizace"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Umožňuje aplikaci číst nastavení synchronizace v účtu. Může například určit, zda je s účtem synchronizována aplikace Lidé."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 45f02e363fe9..bcca73465b9a 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -194,11 +194,11 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratoren har gjort personlig brug af enheden utilgængelig"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Dette er en administreret enhed"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string> - <string name="location_changed_notification_title" msgid="3620158742816699316">"Apps kan få adgang til din placering"</string> + <string name="location_changed_notification_title" msgid="3620158742816699316">"Apps kan få adgang til din lokation"</string> <string name="location_changed_notification_text" msgid="7158423339982706912">"Kontakt din it-administrator for at få flere oplysninger"</string> - <string name="geofencing_service" msgid="3826902410740315456">"Geografisk placeringstjeneste"</string> + <string name="geofencing_service" msgid="3826902410740315456">"Tjeneste til geografisk afgrænsning"</string> <string name="country_detector" msgid="7023275114706088854">"Landeregistrering"</string> - <string name="location_service" msgid="2439187616018455546">"Placeringstjeneste"</string> + <string name="location_service" msgid="2439187616018455546">"Lokationstjeneste"</string> <string name="gnss_service" msgid="8907781262179951385">"GNSS-tjeneste"</string> <string name="sensor_notification_service" msgid="7474531979178682676">"Tjenesten Sensor Notification"</string> <string name="twilight_service" msgid="8964898045693187224">"Tjenesten Twilight"</string> @@ -304,8 +304,8 @@ <string name="managed_profile_label" msgid="7316778766973512382">"Skift til arbejdsprofil"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"Kontakter"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"have adgang til dine kontakter"</string> - <string name="permgrouplab_location" msgid="1858277002233964394">"Placering"</string> - <string name="permgroupdesc_location" msgid="1995955142118450685">"få adgang til enhedens placering"</string> + <string name="permgrouplab_location" msgid="1858277002233964394">"Lokation"</string> + <string name="permgroupdesc_location" msgid="1995955142118450685">"få adgang til enhedens lokation"</string> <string name="permgrouplab_calendar" msgid="6426860926123033230">"Kalender"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"have adgang til din kalender"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Sms"</string> @@ -434,14 +434,14 @@ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Denne app kan tilføje, fjerne eller ændre kalenderbegivenheder på din tablet. Denne app kan sende meddelelser, der kan se ud, som om de kommer fra kalenderejere, eller ændre begivenheder uden at give ejeren besked."</string> <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Denne app kan tilføje, fjerne eller ændre kalenderbegivenheder på din Android TV-enhed. Denne app kan sende meddelelser, der lader til at stamme fra kalenderejere, eller ændre begivenheder uden at give ejeren besked."</string> <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Denne app kan tilføje, fjerne eller ændre kalenderbegivenheder på din telefon. Denne app kan sende meddelelser, der kan se ud, som om de kommer fra kalenderejere, eller ændre begivenheder uden at give ejeren besked."</string> - <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"få adgang til yderligere kommandoer for placeringsudbyder"</string> - <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Tillader, at appen kan få adgang til yderligere kommandoer for placeringsudbydere. Dette kan gøre det muligt for appen at forstyrre GPS-funktionen eller andre placeringskilder."</string> - <string name="permlab_accessFineLocation" msgid="6426318438195622966">"få kun adgang til nøjagtig placering i forgrunden"</string> - <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Denne app kan finde din nøjagtige placering via placeringstjenester, når appen er i brug. Placeringstjenester skal være aktiveret på din enhed, før appen kan finde din placering. Dette kan øge batteriforbruget."</string> - <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"få kun adgang til omtrentlig placering i forgrunden"</string> - <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Denne app kan finde din omtrentlige placering via placeringstjenester, når appen er i brug. Placeringstjenester skal være aktiveret på din enhed, før appen kan finde din placering."</string> - <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"adgang til placering i baggrunden"</string> - <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Denne app kan til enhver tid få adgang til din placering, selv når den ikke er i brug."</string> + <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"få adgang til yderligere kommandoer for lokationsudbyder"</string> + <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Tillader, at appen kan få adgang til yderligere kommandoer for lokationsudbydere. Dette kan gøre det muligt for appen at forstyrre GPS-funktionen eller andre lokationskilder."</string> + <string name="permlab_accessFineLocation" msgid="6426318438195622966">"få kun adgang til nøjagtig lokation i forgrunden"</string> + <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Denne app kan finde din nøjagtige lokation via lokationstjenester, når appen er i brug. Lokationstjenester skal være aktiveret på din enhed, før appen kan finde din lokation. Dette kan øge batteriforbruget."</string> + <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"få kun adgang til omtrentlig lokation i forgrunden"</string> + <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Denne app kan finde din omtrentlige lokation via lokationstjenester, når appen er i brug. Lokationstjenester skal være aktiveret på din enhed, før appen kan finde din lokation."</string> + <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"adgang til lokation i baggrunden"</string> + <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Denne app kan til enhver tid få adgang til din lokation, selv når den ikke er i brug."</string> <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"skifte dine lydindstillinger"</string> <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tillader, at appen kan ændre globale lydindstillinger, som f.eks. lydstyrke og hvilken højttaler der bruges til output."</string> <string name="permlab_recordAudio" msgid="1208457423054219147">"optage lyd"</string> @@ -561,8 +561,8 @@ <string name="permdesc_videoWrite" msgid="6124731210613317051">"Tillader, at appen kan ændre din videosamling."</string> <string name="permlab_imagesWrite" msgid="1774555086984985578">"ændre din billedsamling"</string> <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillader, at appen kan ændre din billedsamling."</string> - <string name="permlab_mediaLocation" msgid="7368098373378598066">"læse placeringer fra din mediesamling"</string> - <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillader, at appen kan læse placeringer fra din mediesamling."</string> + <string name="permlab_mediaLocation" msgid="7368098373378598066">"læse lokationer fra din mediesamling"</string> + <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillader, at appen kan læse lokationer fra din mediesamling."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Brug biometri"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Brug biometri eller skærmlås"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekræft, at det er dig"</string> @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Brug dit fingeraftryk eller din skærmlås for at fortsætte"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Noget gik galt. Prøv igen."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeraftryk"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansigtslås"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Der er et problem med Ansigtslås"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Brug din ansigts- eller skærmlås for at fortsætte"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Noget gik galt. Prøv igen."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ansigt"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"læse indstillinger for synkronisering"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tillader, at appen kan læse synkroniseringsindstillingerne for en konto. Denne tilladelse kan f.eks. fastslå, om appen Personer er synkroniseret med en konto."</string> @@ -1525,8 +1527,8 @@ <string name="websearch" msgid="5624340204512793290">"Websøgning"</string> <string name="find_next" msgid="5341217051549648153">"Find næste"</string> <string name="find_previous" msgid="4405898398141275532">"Find forrige"</string> - <string name="gpsNotifTicker" msgid="3207361857637620780">"Placeringsanmodning fra <xliff:g id="NAME">%s</xliff:g>"</string> - <string name="gpsNotifTitle" msgid="1590033371665669570">"Placeringsanmodning"</string> + <string name="gpsNotifTicker" msgid="3207361857637620780">"Lokationsanmodning fra <xliff:g id="NAME">%s</xliff:g>"</string> + <string name="gpsNotifTitle" msgid="1590033371665669570">"Lokationsanmodning"</string> <string name="gpsNotifMessage" msgid="7346649122793758032">"Anmodet om af <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string> <string name="gpsVerifYes" msgid="3719843080744112940">"Ja"</string> <string name="gpsVerifNo" msgid="1671201856091564741">"Nej"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 865f02663299..c9d86790c3d2 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Verwende deinen Fingerabdruck oder deine Display-Entsperrmethode, um fortzufahren"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Ein Problem ist aufgetreten. Versuch es noch einmal."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerabdruck-Symbol"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Entsperrung per Gesichtserkennung"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem bei der Entsperrung per Gesichtserkennung"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Verwende die Gesichtserkennung oder deine Display-Entsperrmethode, um fortzufahren"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Ein Problem ist aufgetreten. Versuch es noch einmal."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Gesichtssymbol"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"Synchronisierungseinstellungen lesen"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 67bd43325cf7..a8dcc4f835e8 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Χρησιμοποιήστε το δακτυλικό σας αποτύπωμα ή το κλείδωμα οθόνης για να συνεχίσετε"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ξεκλείδωμα με το πρόσωπο"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Πρόβλημα με το Ξεκλείδωμα με το πρόσωπο"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Χρησιμοποιήστε το πρόσωπό σας ή το κλείδωμα οθόνης για συνέχεια"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Εικ. προσ."</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"διαβάζει τις ρυθμίσεις συγχρονισμού"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 8cf968d503a7..c268eda05323 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index b772335a6438..5e5ffbe49268 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index e1e81870cfa3..c65b8bbdbfdc 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 892041c2332d..baa35172c964 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index a7ad2b6dc16a..dcf237ed3929 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 5206c484b893..8987cda96efa 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella dactilar o bloqueo de pantalla para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Se produjo un error. Vuelve a intentarlo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella dactilar"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con el Desbloqueo facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu rostro o bloqueo de pantalla para continuar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Se produjo un error. Vuelve a intentarlo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ícono cara"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"leer la configuración de sincronización"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 9a29addc10b0..6673d2780636 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella digital o tu bloqueo de pantalla para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Se ha producido un error. Inténtalo de nuevo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icono de huella digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con Desbloqueo facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu cara o tu bloqueo de pantalla para continuar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Se ha producido un error. Inténtalo de nuevo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Icono cara"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"leer la configuración de sincronización"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 4dd7d9469f4c..b76e7e3ddf7a 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jätkamiseks kasutage oma sõrmejälge või ekraanilukku"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Midagi läks valesti. Proovige uuesti."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Näoga avamine"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem funktsiooniga Näoga avamine"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jätkamiseks kasutage oma nägu või ekraanilukku"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Midagi läks valesti. Proovige uuesti."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Näoikoon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"loe sünkroonimisseadeid"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Võimaldab rakendusel lugeda konto sünkroonimisseadeid. Näiteks võib see määrata, kas rakendus Inimesed on kontoga sünkroonitud."</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index d4705c100a8f..cc394dddc4fd 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aurrera egiteko, erabili hatz-marka edo pantailaren blokeoa"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Arazoren bat izan da. Saiatu berriro."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Aurpegi bidez desblokeatzeko eginbidea"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arazoak ditugu aurpegi bidez desblokeatzeko eginbidearekin"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aurrera egiteko, erabili aurpegia edo pantailaren blokeoa"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Arazoren bat izan da. Saiatu berriro."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Aurpegiaren ikonoa"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"irakurri sinkronizazio-ezarpenak"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Kontu baten sinkronizazio-ezarpenak irakurtzeko baimena ematen die aplikazioei. Adibidez, Jendea aplikazioa konturen batekin sinkronizatuta dagoen zehatz dezake."</string> @@ -1312,7 +1314,7 @@ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string> <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Sakatu hala ere konektatzeko"</string> <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string> - <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string> + <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Baliteke zerbait ordaindu behar izatea."</string> <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string> <string-array name="network_switch_type_name"> <item msgid="2255670471736226365">"datu-konexioa"</item> @@ -1985,7 +1987,7 @@ <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikazioa Android-en bertsio zaharrago baterako sortu zenez, baliteke behar bezala ez funtzionatzea. Bilatu eguneratzerik baden, edo jarri garatzailearekin harremanetan."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Bilatu eguneratzeak"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Mezu berriak dituzu"</string> - <string name="new_sms_notification_content" msgid="3197949934153460639">"Mezuak ikusteko, ireki SMS mezuetarako aplikazioa"</string> + <string name="new_sms_notification_content" msgid="3197949934153460639">"Mezuak ikusteko, ireki SMSetarako aplikazioa"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"Baliteke funtzio batzuk mugatuta egotea"</string> <string name="profile_encrypted_detail" msgid="5279730442756849055">"Blokeatuta dago laneko profila"</string> <string name="profile_encrypted_message" msgid="1128512616293157802">"Sakatu profila desblokeatzeko"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index fcca1b39330a..5155dfa9071b 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"برای ادامه، از اثر انگشت یا قفل صفحه استفاده کنید"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"مشکلی پیش آمد. دوباره امتحان کنید."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"نماد اثر انگشت"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"قفلگشایی با چهره"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"مشکل در «قفلگشایی با چهره»"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"برای ادامه، از تشخیص چهره یا قفل صفحه استفاده کنید"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"مشکلی پیش آمد. دوباره امتحان کنید."</string> <string name="face_icon_content_description" msgid="465030547475916280">"نماد چهره"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"خواندن تنظیمات همگامسازی"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"به برنامه اجازه میدهد تنظیمات را برای یک حساب بخواند. بهعنوان مثال، این ویژگی میتواند تعیین کند آیا حساب «افراد» شما با یک حساب همگامسازی شده است."</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 5998269aae48..1e491e5b7482 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jatka sormenjäljen tai näytön lukituksen avulla"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Jotain meni vikaan. Yritä uudelleen."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sormenjälkikuvake"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Kasvojentunnistusavaus"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Face Unlockiin liittyvä ongelma"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jatka kasvojentunnistuksen tai näytön lukituksen avulla"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Jotain meni vikaan. Yritä uudelleen."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Kasvokuvake"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lue synkronointiasetuksia"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Antaa sovelluksen lukea tilien synkronointiasetuksia. Sovellus voi esimerkiksi määrittää, onko Henkilöt-sovellus synkronoitu tilin kanssa."</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 860e10bcff4d..a0a652527f52 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilisez votre empreinte digitale ou le verrouillage de l\'écran pour continuer"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Un problème est survenu. Réessayez."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème avec la fonctionnalité de déverrouillage par reconnaissance faciale"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez votre visage ou le verrouillage de l\'écran pour continuer"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Un problème est survenu. Réessayez."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 55fa1453caf8..b1a7eece28ed 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilisez votre empreinte digitale ou le verrouillage de l\'écran pour continuer"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Un problème est survenu. Réessayez."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème lié au déverrouillage par reconnaissance faciale"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez la reconnaissance faciale ou le verrouillage de l\'écran pour continuer"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Un problème est survenu. Réessayez."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 76f54ff26b09..50117568dad4 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Para continuar, utiliza a impresión dixital ou o bloqueo de pantalla"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Produciuse un erro. Téntao de novo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona de impresión dixital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Produciuse un problema co desbloqueo facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Para continuar, utiliza o desbloqueo facial ou a credencial do dispositivo"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Produciuse un erro. Téntao de novo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Icona cara"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler a configuración de vinculación"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite á aplicación ler a configuración de vinculación dunha conta. Por exemplo, esta acción pode determinar se a aplicación Contactos se vincula cunha conta."</string> @@ -981,7 +983,7 @@ <string name="js_dialog_before_unload_title" msgid="7012587995876771246">"Confirmar navegación"</string> <string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"Abandonar esta páxina"</string> <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"Permanecer nesta páxina"</string> - <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nEstás seguro de que queres saír desta páxina?"</string> + <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSeguro que queres saír desta páxina?"</string> <string name="save_password_label" msgid="9161712335355510035">"Confirmar"</string> <string name="double_tap_toast" msgid="7065519579174882778">"Consello: Toca dúas veces para achegar e afastar o zoom."</string> <string name="autofill_this_form" msgid="3187132440451621492">"Encher"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 3422d8e62f9d..e1d89ab6ab73 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ચાલુ રાખવા માટે તમારા ફિંગરપ્રિન્ટ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ફિંગરપ્રિન્ટ આયકન"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ફેસ અનલૉક"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ફેસ અનલૉકની સુવિધામાં સમસ્યા"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ચાલુ રાખવા માટે તમારા ફેસ લૉક અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string> <string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"સિંક સેટિંગ વાંચો"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ સિંક થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string> @@ -950,7 +952,7 @@ <string name="keyguard_accessibility_widget" msgid="6776892679715699875">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> વિજેટ."</string> <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"વપરાશકર્તા પસંદગીકર્તા"</string> <string name="keyguard_accessibility_status" msgid="6792745049712397237">"સ્થિતિ"</string> - <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"કૅમેરો"</string> + <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"કૅમેરા"</string> <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"મીડિયા નિયંત્રણો"</string> <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"વિજેટ પુનઃક્રમાંકન પ્રારંભ થયું."</string> <string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"વિજેટ પુનઃક્રમાંકન સમાપ્ત થયું."</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 8e2c2007f9ee..1440f40c436e 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"जारी रखने के लिए, फ़िंगरप्रिंट या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फ़िंगरप्रिंट आइकॉन"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फ़ेस अनलॉक"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फ़ेस अनलॉक से जुड़ी समस्या"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी रखने के लिए, अपना चेहरा दिखाकर या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string> <string name="face_icon_content_description" msgid="465030547475916280">"चेहरे का आइकॉन"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"समन्वयन सेटिंग पढ़ें"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ऐप्स को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह तय किया जा सकता है कि लोग ऐप्स किसी खाते के साथ समन्वयित है या नहीं."</string> @@ -2008,7 +2010,7 @@ <string name="app_category_image" msgid="7307840291864213007">"फ़ोटो और तस्वीरें"</string> <string name="app_category_social" msgid="2278269325488344054">"सामाजिक और संचार"</string> <string name="app_category_news" msgid="1172762719574964544">"समाचार और पत्रिकाएं"</string> - <string name="app_category_maps" msgid="6395725487922533156">"Maps और नेविगेशन ऐप्लिकेशन"</string> + <string name="app_category_maps" msgid="6395725487922533156">"मैप और नेविगेशन ऐप्लिकेशन"</string> <string name="app_category_productivity" msgid="1844422703029557883">"उत्पादकता"</string> <string name="app_category_accessibility" msgid="6643521607848547683">"सुलभता"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"डिवाइस में जगह"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 9aa3350d6ecd..7dd2ad39891f 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -612,6 +612,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Za nastavak se identificirajte otiskom prsta ili vjerodajnicom zaključavanja zaslona"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Nešto nije u redu. Pokušajte ponovo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Poteškoće s otključavanjem licem"</string> @@ -664,6 +665,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nastavak se identificirajte licem ili vjerodajnicom zaključavanja zaslona"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Nešto nije u redu. Pokušajte ponovo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje postavki sinkronizacije"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Aplikaciji omogućuje čitanje postavki sinkronizacije za račun. Time se, primjerice, može utvrditi je li aplikacija Osobe sinkronizirana s računom."</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 908b77956b44..0e20f2051c29 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"A folytatás ujjlenyomattal vagy a képernyőzár feloldásával lehetséges"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Hiba történt. Próbálja újra."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ujjlenyomat ikon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Arcalapú feloldás"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arcalapú feloldással kapcsolatos problémák"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"A folytatás arcalapú feloldással vagy a képernyőzár feloldásával lehetséges"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Hiba történt. Próbálja újra."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Arcikon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"szinkronizálási beállítások olvasása"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lehetővé teszi az alkalmazás számára egy fiók szinkronizálási beállításainak beolvasását. Például ellenőrizheti, hogy a Személyek alkalmazás szinkronizálva van-e egy fiókkal."</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index a7992f968ea0..f94c8114a0e6 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -177,7 +177,7 @@ <string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"Չի հաջողվում համաժամացնել"</string> <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"Հետևյալ ծառայությունից չափազանց շատ տարրեր եք ջնջել՝ <xliff:g id="CONTENT_TYPE">%s</xliff:g>:"</string> <string name="low_memory" product="tablet" msgid="5557552311566179924">"Պլանշետի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</string> - <string name="low_memory" product="watch" msgid="3479447988234030194">"Ժամացույցի ֆայլերի պահեստը լիքն է: Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string> + <string name="low_memory" product="watch" msgid="3479447988234030194">"Ժամացույցի ֆայլերի պահոցը լիքն է: Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string> <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV սարքի հիշողությունը լցված է։ Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string> <string name="low_memory" product="default" msgid="2539532364144025569">"Հեռախոսի պահոցը լիքն է: Ջնջեք մի քանի ֆայլեր` տարածություն ազատելու համար:"</string> <plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029"> @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Շարունակելու համար օգտագործեք ձեր մատնահետքը կամ էկրանի կողպումը"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Սխալ առաջացավ։ Նորից փորձեք։"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Մատնահետքի պատկերակ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Դեմքով ապակողպում"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Դեմքով ապակողպման հետ կապված խնդիր"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Շարունակելու համար օգտագործեք ձեր դեմքը կամ էկրանի կողպումը"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Սխալ առաջացավ։ Նորից փորձեք։"</string> <string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"կարդալ համաժամացման կարգավորումները"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ՝ այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index f31746b3ed7c..5f9ad9d7d456 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gunakan sidik jari atau kunci layar untuk melanjutkan"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Terjadi error. Coba lagi."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon sidik jari"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Masalah pada Face Unlock"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan face lock atau kunci layar untuk melanjutkan"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Terjadi error. Coba lagi."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"baca setelan sinkronisasi"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Memungkinkan aplikasi membaca setelan sinkronisasi untuk sebuah akun. Misalnya, izin ini dapat menentukan apakah aplikasi Orang disinkronkan dengan sebuah akun."</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 93e25a6b014e..76c583720c4d 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Notaðu fingrafar eða skjálás til að halda áfram"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Eitthvað fór úrskeiðis. Reyndu aftur."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingrafaratákn"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Andlitskenni"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Vandamál varðandi andlitskenni"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Notaðu andlitið eða skjálás til að halda áfram"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Eitthvað fór úrskeiðis. Reyndu aftur."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Andlitstákn"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lesa samstillingar"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Leyfir forriti að lesa kosti samstillingar fyrir reikning. Þetta er til dæmis hægt að nota til að komast að því hvort forritið Fólk er samstillt við reikning."</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 316514e6cc29..c4493a188a22 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Per continuare devi usare la tua impronta o il tuo blocco schermo"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Si è verificato un errore. Riprova."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona dell\'impronta"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Sblocco con il volto"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con Sblocco con il volto"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Per continuare devi usare il tuo volto o il tuo blocco schermo"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Si è verificato un errore. Riprova."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Icona volto"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lettura impostazioni di sincronizz."</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 716e97c70768..02ff0f561e58 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"יש להשתמש בטביעת האצבע או בנעילת המסך כדי להמשיך"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"משהו השתבש. עליך לנסות שוב."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"סמל טביעת אצבע"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"פתיחה ע\"י זיהוי הפנים"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"בעיה בפתיחה ע\"י זיהוי הפנים"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"יש להשתמש בזיהוי הפנים או בנעילת המסך כדי להמשיך"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"משהו השתבש. עליך לנסות שוב."</string> <string name="face_icon_content_description" msgid="465030547475916280">"סמל הפנים"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"קריאת הגדרות הסנכרון"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"מאפשרת לאפליקציה לקרוא את הגדרות הסנכרון של חשבון. לדוגמה, כך אפשר לדעת אם האפליקציה \'אנשים\' מסונכרנת עם חשבון כלשהו."</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 30a62e3d8df0..0ef14c2c82a2 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"続行するには、指紋認証または画面ロックを使用してください"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"エラーが発生しました。もう一度お試しください。"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋アイコン"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"顔認証"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"顔認証に関する問題"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"続行するには、顔認証または画面ロックを使用してください"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"エラーが発生しました。もう一度お試しください。"</string> <string name="face_icon_content_description" msgid="465030547475916280">"顔アイコン"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"同期設定の読み取り"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 789e2794e083..b29ce0aa3795 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი ან ეკრანის განბლოკვის ნიმუში"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"თითის ანაბეჭდის ხატულა"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"განბლოკვა სახით"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"პრობლემა სახით განბლოკვასთან დაკავშირებით"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"გასაგრძელებლად გამოიყენეთ თქვენი სახე ან ეკრანის განბლოკვის ნიმუში"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string> <string name="face_icon_content_description" msgid="465030547475916280">"სახის ხატულა"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"სინქრონიზაციის პარამეტრების წაკითხვა"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"აპს შეეძლება, წაიკითხოს ანგარიშის სინქრონიზაციის პარამეტრები. მაგალითად, მას შეეძლება განსაზღვროს, არის თუ არა People აპი სინქრონიზებული ანგარიშთან."</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 6e8281326606..f2fe39ed5045 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -278,7 +278,7 @@ <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Физикалық пернетақта"</string> <string name="notification_channel_security" msgid="8516754650348238057">"Қауіпсіздік"</string> <string name="notification_channel_car_mode" msgid="2123919247040988436">"Көлік режимі"</string> - <string name="notification_channel_account" msgid="6436294521740148173">"Есептік жазба күйі"</string> + <string name="notification_channel_account" msgid="6436294521740148173">"Аккаунт күйі"</string> <string name="notification_channel_developer" msgid="1691059964407549150">"Әзірлеуші хабарлары"</string> <string name="notification_channel_developer_important" msgid="7197281908918789589">"Әзірлеушілердің маңызды хабарлары"</string> <string name="notification_channel_updates" msgid="7907863984825495278">"Жаңартылған нұсқалар"</string> @@ -411,9 +411,9 @@ <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Қолданба трансляция біткеннен кейін сақталатын бекітілген трансляцияларды жібере алатын болады. Тым жиі пайдалансаңыз, жад толып, Android TV құрылғысы баяу немесе тұрақсыз жұмыс істеуі мүмкін."</string> <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Қолданбаға хабар тарату аяқталғанда сақталатын жабысқақ хабар тарату мүмкіндігін береді. Тым көп қолдану телефон жұмысын баяулатады немесе жадты көп қолдану арқылы жұмысын тұрақсыздандырады."</string> <string name="permlab_readContacts" msgid="8776395111787429099">"контактілерді оқу"</string> - <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Қолданбаға планшетте сақталған контактілеріңіз туралы деректерді оқуға рұқсат етеді. Қолданбалар контактілер жасалған планшеттегі есептік жазбаларды пайдалана алады. Бұған сіз орнатқан қолданбалар арқылы жасалған есептік жазбалар кіруі мүмкін. Бұл рұқсат қолданбаларға контакт деректерін сақтау мүмкіндігін береді және зиянды қолданбалар контакт деректерін сіздің келісіміңізсіз бөлісуі ықтимал."</string> - <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Қолданбаға Android TV құрылғысында сақталған контактілеріңіз туралы деректерді оқуға рұқсат етеді. Қолданба контактілер жасалған Android TV құрылғысындағы есептік жазбаларды пайдалана алады. Бұған сіз орнатқан қолданбалар арқылы жасалған есептік жазбалар кіруі мүмкін. Бұл рұқсат қолданбаларға контакт деректерін сақтау мүмкіндігін береді және зиянды қолданбалар контакт деректерін сіздің келісіміңізсіз бөлісуі ықтимал."</string> - <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Қолданбаға телефонда сақталған контактілеріңіз туралы деректерді оқуға рұқсат етеді. Қолданбалар контактілер жасалған телефондағы есептік жазбаларды пайдалана алады. Бұған сіз орнатқан қолданбалар арқылы жасалған есептік жазбалар кіруі мүмкін. Бұл рұқсат қолданбаларға контакт деректерін сақтау мүмкіндігін береді және зиянды қолданбалар контакт деректерін сіздің келісіміңізсіз бөлісуі ықтимал."</string> + <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Қолданбаға планшетте сақталған контактілеріңіз туралы деректерді оқуға рұқсат етеді. Қолданбалар контактілер жасалған планшеттегі аккаунттарды пайдалана алады. Бұған сіз орнатқан қолданбалар арқылы жасалған аккаунттар кіруі мүмкін. Бұл рұқсат қолданбаларға контакт деректерін сақтау мүмкіндігін береді және зиянды қолданбалар контакт деректерін сіздің келісіміңізсіз бөлісуі ықтимал."</string> + <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Қолданбаға Android TV құрылғысында сақталған контактілеріңіз туралы деректерді оқуға рұқсат етеді. Қолданба контактілер жасалған Android TV құрылғысындағы аккаунттарды пайдалана алады. Бұған сіз орнатқан қолданбалар арқылы жасалған аккаунттар кіруі мүмкін. Бұл рұқсат қолданбаларға контакт деректерін сақтау мүмкіндігін береді және зиянды қолданбалар контакт деректерін сіздің келісіміңізсіз бөлісуі ықтимал."</string> + <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Қолданбаға телефонда сақталған контактілеріңіз туралы деректерді оқуға рұқсат етеді. Қолданбалар контактілер жасалған телефондағы аккаунттарды пайдалана алады. Бұған сіз орнатқан қолданбалар арқылы жасалған аккаунттар кіруі мүмкін. Бұл рұқсат қолданбаларға контакт деректерін сақтау мүмкіндігін береді және зиянды қолданбалар контакт деректерін сіздің келісіміңізсіз бөлісуі ықтимал."</string> <string name="permlab_writeContacts" msgid="8919430536404830430">"контактілерді өзгерту"</string> <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Қолданбаға планшетте сақталған контактілеріңіз туралы деректерді өзгертуге рұқсат етеді. Бұл рұқсат қолданбаларға контактілер туралы деректерді жоюға рұқсат береді."</string> <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Қолданбаға Android TV құрылғысында сақталған контактілеріңіз туралы деректерді өзгертуге рұқсат етеді. Бұл рұқсат қолданбаларға контактілер туралы деректерді жоюға рұқсат береді."</string> @@ -499,10 +499,10 @@ <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"Қолданбаға планшеттің уақыт белдеуін өзгертуге рұқсат береді."</string> <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"Қолданба Android TV құрылғыңыздың уақыт белдеуін өзгерте алатын болады."</string> <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Қолданбаға телефонның уақыт белдеуін өзгертуге рұқсат береді."</string> - <string name="permlab_getAccounts" msgid="5304317160463582791">"құрылғыдағы есептік жазбаларды табу"</string> - <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Қолданбаға планшет арқылы белгілі есептік жазбалар тізімін алу мүмкіндігін береді. Сіз орнатқан қолданбалар жасақтаған есептік жазбалар да қамтылуы мүмкін."</string> - <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Қолданба Android TV құрылғыңыз танитын есептік жазбалардың тізімін ала алатын болады. Оған сіз орнатқан қолданбалар арқылы жасалған кез келген есептік жазба кіруі мүмкін."</string> - <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Қолданбаға телефон арқылы белгілі есептік жазбалар тізімін алу мүмкіндігін береді. Сіз орнатқан қолданбалар жасақтаған есептік жазбалар да қамтылуы мүмкін."</string> + <string name="permlab_getAccounts" msgid="5304317160463582791">"құрылғыдағы аккаунттарды табу"</string> + <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Қолданбаға планшет арқылы белгілі аккаунттар тізімін алу мүмкіндігін береді. Сіз орнатқан қолданбалар жасақтаған аккаунттар да қамтылуы мүмкін."</string> + <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Қолданба Android TV құрылғыңыз танитын аккаунтлардың тізімін ала алатын болады. Оған сіз орнатқан қолданбалар арқылы жасалған кез келген аккаунт кіруі мүмкін."</string> + <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Қолданбаға телефон арқылы белгілі аккаунттар тізімін алу мүмкіндігін береді. Сіз орнатқан қолданбалар жасақтаған аккаунттар да қамтылуы мүмкін."</string> <string name="permlab_accessNetworkState" msgid="2349126720783633918">"желі байланыстарын көру"</string> <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Қолданбаға желі байланысы туралы ақпаратты, мысалы, қайсысы бар және қосылған деген сияқты, көру мүмкіндігін береді."</string> <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"желіге толық қатынасы бар"</string> @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Жалғастыру үшін саусақ ізін немесе экран құлпын пайдаланыңыз."</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Саусақ ізі белгішесі"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Бет тану"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Бет тану функциясына қатысты мәселе шықты"</string> @@ -661,13 +662,14 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Жалғастыру үшін бетті анықтау функциясын немесе экран құлпын пайдаланыңыз."</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Бет белгішесі"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"синх параметрлерін оқу"</string> - <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Қолданбаға есептік жазба синхрондау параметрлерін оқу мүмкіндігін береді. Мысалы, бұл арқылы People қолданбасының есептік жазбамен сихрондалғаны анықталуы мүмкін."</string> + <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Қолданбаға аккаунт синхрондау параметрлерін оқу мүмкіндігін береді. Мысалы, бұл арқылы People қолданбасының аккаунтмен сихрондалғаны анықталуы мүмкін."</string> <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"синх қосу және өшіру арасында ауысу"</string> - <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Қолданбаға есептік жазбаның синхрондау параметрлерін жөндеу мүмкіндігін береді. Мысалы, бұл People қолданбасын есептік жазбамен синхрондауды қосу үшін қолданылуы мүмкін."</string> + <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Қолданбаға аккаунттың синхрондау параметрлерін жөндеу мүмкіндігін береді. Мысалы, бұл People қолданбасын аккаунтпен синхрондауды қосу үшін қолданылуы мүмкін."</string> <string name="permlab_readSyncStats" msgid="3747407238320105332">"үйлестіру санақтық ақпаратын оқу"</string> - <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Қолданбаға есептік жазбаның синхрондалу статистикаларын, оның ішінде синхрондау шараларының тарихы және қанша дерек синхрондалғаны жайлы, оқу мүмкіндігін береді."</string> + <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Қолданбаға аккаунттың синхрондалу статистикаларын, оның ішінде синхрондау шараларының тарихы және қанша дерек синхрондалғаны жайлы, оқу мүмкіндігін береді."</string> <string name="permlab_sdcardRead" msgid="5791467020950064920">"ортақ жадтың мазмұнын оқу"</string> <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Қолданбаға ортақ жадтың мазмұнын оқуға мүмкіндік береді."</string> <string name="permlab_sdcardWrite" msgid="4863021819671416668">"ортақ жадтың мазмұнын өзгерту немесе жою"</string> @@ -690,7 +692,7 @@ <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Қолданбаға белгілі бір желілер және қолданбалар үшін журналдық желіні пайдалануды оқуға рұқсат береді."</string> <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"желі саясатын басқару"</string> <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Қолданбаға желілік саясаттарды басқаруға және қолданба ережелерін анықтауға рұқсат береді."</string> - <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"желіні қолдану есептік жазбаларын өзгерту"</string> + <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"желіні қолдану аккаунттарын өзгерту"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Қолданбаға қолданбалардың желіні қолдану әрекетін өзгерту мүмкіндігін береді. Қалыпты қолданбалар қолданысына арналмаған."</string> <string name="permlab_accessNotifications" msgid="7130360248191984741">"хабарларға кіру"</string> <string name="permdesc_accessNotifications" msgid="761730149268789668">"Қолданбаға хабарларды алу, тексеру және тазалау мүмкіндігін береді, басқа қолданбалар арқылы қойылған хабарларды қоса."</string> @@ -924,7 +926,7 @@ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Телефонды ашуға <xliff:g id="NUMBER">%d</xliff:g> рет қате әрекеттендіңіз. Телефон зауыттың бастапқы параметрлеріне қайта реттеледі."</string> <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string> <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Кескінді ұмытып қалдыңыз ба?"</string> - <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Есептік жазбаның бекітпесін ашу"</string> + <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Аккаунттың бекітпесін ашу"</string> <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Тым көп кескін әрекеттері"</string> <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ашу үшін Google есептік жазбаңызбен кіріңіз."</string> <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Пайдаланушы атауы (эл. пошта)"</string> @@ -1481,8 +1483,8 @@ <string name="allow" msgid="6195617008611933762">"Рұқсат беру"</string> <string name="deny" msgid="6632259981847676572">"Тыйым салу"</string> <string name="permission_request_notification_title" msgid="1810025922441048273">"Рұқсат өтінілді"</string> - <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Рұқсат \nесептік жазба үшін <xliff:g id="ACCOUNT">%s</xliff:g> өтінілді."</string> - <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы үшін <xliff:g id="APP">%1$s</xliff:g>\nқолданбасы арқылы рұқсат сұралды."</string> + <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Рұқсат \nаккаунт үшін <xliff:g id="ACCOUNT">%s</xliff:g> өтінілді."</string> + <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты үшін <xliff:g id="APP">%1$s</xliff:g>\nқолданбасы арқылы рұқсат сұралды."</string> <string name="forward_intent_to_owner" msgid="4620359037192871015">"Осы қолданбаны жұмыс профиліңізден тыс пайдаланып жатырсыз"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"Осы қолданбаны жұмыс профиліңізде пайдаланып жатырсыз"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"Енгізу әдісі"</string> @@ -1531,13 +1533,13 @@ <string name="gpsVerifYes" msgid="3719843080744112940">"Иә"</string> <string name="gpsVerifNo" msgid="1671201856091564741">"Жоқ"</string> <string name="sync_too_many_deletes" msgid="6999440774578705300">"Жою шектеуінен асып кетті"</string> - <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"Мұнда <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> жойылған <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> есептік жазбасының элементі бар. Не істеуді қалайсыз?"</string> + <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"Мұнда <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> жойылған <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> аккаунтының элементі бар. Не істеуді қалайсыз?"</string> <string name="sync_really_delete" msgid="5657871730315579051">"Бұл нәрселер жойылсын"</string> <string name="sync_undo_deletes" msgid="5786033331266418896">"Жойылғандарды кері орындау"</string> <string name="sync_do_nothing" msgid="4528734662446469646">"Қазір ешқандай әрекет жасамаңыз"</string> - <string name="choose_account_label" msgid="5557833752759831548">"Есептік жазба таңдау"</string> - <string name="add_account_label" msgid="4067610644298737417">"Есептік жазба қосу"</string> - <string name="add_account_button_label" msgid="322390749416414097">"Есептік жазба қосу."</string> + <string name="choose_account_label" msgid="5557833752759831548">"Аккаунт таңдау"</string> + <string name="add_account_label" msgid="4067610644298737417">"Аккаунт қосу"</string> + <string name="add_account_button_label" msgid="322390749416414097">"Аккаунт қосу."</string> <string name="number_picker_increment_button" msgid="7621013714795186298">"Арттыру"</string> <string name="number_picker_decrement_button" msgid="5116948444762708204">"Азайту"</string> <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> түймесін басып тұрыңыз."</string> @@ -1665,13 +1667,13 @@ <string name="kg_invalid_puk" msgid="4809502818518963344">"Дұрыс PUK кодын қайта енгізіңіз. Әрекеттерді қайталау SIM картасының істен шығуына себеп болады."</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN коды сәйкес емес."</string> <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Тым көп кескін әрекеттері"</string> - <string name="kg_login_instructions" msgid="3619844310339066827">"Ашу үшін Google есептік жазбасы арқылы кіріңіз."</string> + <string name="kg_login_instructions" msgid="3619844310339066827">"Ашу үшін Google аккаунты арқылы кіріңіз."</string> <string name="kg_login_username_hint" msgid="1765453775467133251">"Пайдаланушы атауы (эл. пошта)"</string> <string name="kg_login_password_hint" msgid="3330530727273164402">"Құпия сөз"</string> <string name="kg_login_submit_button" msgid="893611277617096870">"Кіру"</string> <string name="kg_login_invalid_input" msgid="8292367491901220210">"Пайдаланушы атауы немесе кілтсөз жарамсыз."</string> <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Пайдаланушы атауын немесе кілтсөзді ұмытып қалдыңыз ба?\n"<b>"google.com/accounts/recovery"</b>" веб-сайтына кіріңіз."</string> - <string name="kg_login_checking_password" msgid="4676010303243317253">"Есептік жазбаны тексеруде…"</string> + <string name="kg_login_checking_password" msgid="4676010303243317253">"Аккаунтты тексеруде…"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"PIN кодты <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін қайталаңыз."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Құпия сөзді <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін қайталаңыз."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате салдыңыз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string> @@ -1681,9 +1683,9 @@ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"Планшетті ашуға <xliff:g id="NUMBER">%d</xliff:g> рет қате әрекеттендіңіз. Планшет бастапқы зауыттық параметрлеріне қайта реттеледі."</string> <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"Android TV құрылғыңыздың құлпын <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс ашпадыңыз. Енді Android TV құрылғыңыздың зауыттық әдепкі параметрлері қайтарылады."</string> <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Телефонды ашуға <xliff:g id="NUMBER">%d</xliff:g> рет қате әрекеттендіңіз. Телефон бастапқы зауыттық параметрлеріне қайта реттеледі."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді есептік жазба арқылы ашу өтінішін аласыз.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді аккаунт арқылы ашу өтінішін аласыз.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string> <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет дұрыс сызбадыңыз. Енді тағы <xliff:g id="NUMBER_1">%2$d</xliff:g> рет қателессеңіз, Android TV құрылғыңыздың құлпын ашу үшін есептік жазбаңызға кіру керек болады.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайталап көріңіз."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды аккаунт арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Жою"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string> @@ -1964,8 +1966,8 @@ <string name="importance_from_user" msgid="2782756722448800447">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string> <string name="importance_from_person" msgid="4235804979664465383">"Қатысты адамдарға байланысты бұл маңызды."</string> <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Арнаулы хабар хабарландыруы"</string> - <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы (мұндай есептік жазбаға ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string> - <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string> + <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы (мұндай аккаунтқа ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string> + <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string> <string name="language_selection_title" msgid="52674936078683285">"Тіл қосу"</string> <string name="country_selection_title" msgid="5221495687299014379">"Аймақ параметрі"</string> <string name="search_language_hint" msgid="7004225294308793583">"Тіл атауын теріңіз"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index d56a55ded4a9..8b4d9b63c3ea 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ប្រើការចាក់សោអេក្រង់ ឬស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"រូបស្នាមម្រាមដៃ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ដោះសោតាមទម្រង់មុខ"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"មានបញ្ហាពាក់ព័ន្ធនឹងមុខងារដោះសោតាមទម្រង់មុខ"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ប្រើការចាក់សោអេក្រង់ ឬមុខរបស់អ្នក ដើម្បីបន្ត"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string> <string name="face_icon_content_description" msgid="465030547475916280">"រូបផ្ទៃមុខ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"អានការកំណត់ធ្វើសមកាលកម្ម"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ឲ្យកម្មវិធីអានការកំណត់ធ្វើសមកាលកម្មសម្រាប់គណនី។ ឧទាហរណ៍ វាអាចកំណត់ថាតើកម្មវិធីត្រូវបានបើកជាមួយគណនីដែរឬទេ។"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index c5b57e96e24b..af6df158afbe 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ಮುಂದುವರಿಸಲು ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಐಕಾನ್"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ಫೇಸ್ ಅನ್ಲಾಕ್"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಕುರಿತು ಸಮಸ್ಯೆ ಇದೆ"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಮುಖ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="face_icon_content_description" msgid="465030547475916280">"ಮುಖದ ಐಕಾನ್"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ರೀಡ್ ಮಾಡು"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ಒಂದು ಖಾತೆಯ ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಖಾತೆಯೊಂದಿಗೆ ಜನರ ಅಪ್ಲಿಕೇಶನ್ ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಇದು ನಿರ್ಧರಿಸಬಹುದು."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index ea8fe228896a..1bf33df04aff 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"계속하려면 지문이나 화면 잠금을 사용하세요"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"문제가 발생했습니다. 다시 시도해 보세요."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"지문 아이콘"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"얼굴 인식 잠금 해제"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"얼굴 인식 잠금 해제 문제"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"계속하려면 얼굴 또는 화면 잠금을 사용하세요"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"문제가 발생했습니다. 다시 시도해 보세요."</string> <string name="face_icon_content_description" msgid="465030547475916280">"얼굴 아이콘"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"동기화 설정 읽기"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 421608687033..89b6e1573e78 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Улантуу үчүн манжа изин же экрандын кулпусун колдонуңуз"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Манжа изинин сүрөтчөсү"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Жүзүнөн таанып ачуу"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Жүзүнөн таанып ачуу функциясында маселе келип чыкты"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Улантуу үчүн жүзүңүздү же экрандын кулпусун колдонуңуз"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Жүздүн сүрөтчөсү"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"шайкештирүү жөндөөлөрүн окуу"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Колдонмого эсеп менен синхрондошуу тууралоолорун окуганга уруксат берет. Мисалы, Кишилер колдонмосу эсеп менен синхрондошкондугун аныктай алат."</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index b1c0d591c4fb..9849b2988aca 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ໃຊ້ລາຍນິ້ວມື ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ໄອຄອນລາຍນິ້ວມື"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ປົດລັອກດ້ວຍໜ້າ"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ເກີດບັນຫາກັບການປົດລັອກດ້ວຍໜ້າ"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ໃຊ້ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string> <string name="face_icon_content_description" msgid="465030547475916280">"ໄອຄອນໃບໜ້າ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ອ່ານການຕັ້ງຄ່າຊິ້ງຂໍ້ມູນ"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການຕັ້ງຄ່າການຊິ້ງຂໍ້ມູນຂອງບັນຊີໄດ້. ຕົວຢ່າງເຊັ່ນ: ມັນຈະສາມາດກວດສອບໄດ້ແອັບຯ People ຖືກຊິ້ງຂໍ້ມູນກັບບັນຊີໃດນຶ່ງແລ້ວຫຼືຍັງ."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 1879dcc85513..32cf15edfd4a 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jei norite tęsti, naudokite kontrolinį kodą arba ekrano užraktą"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Kažkas nepavyko. Bandykite dar kartą."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Piršto antspaudo piktograma"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Atrakinimas pagal veidą"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Su atrakinimu pagal veidą susijusi problema"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jei norite tęsti, naudokite veido atpažinimo funkciją arba ekrano užraktą"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Kažkas nepavyko. Bandykite dar kartą."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Veido pkt."</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"skaityti sinchronizavimo nustatymus"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Leidžiama programai skaityti ir sinchronizuoti paskyros nustatymus. Pvz., taip gali būti nustatoma, ar su paskyra sinchronizuota Žmonių programa."</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 15eda966c48c..ff58478b0516 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -612,6 +612,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Izmantojiet pirksta nospiedumu vai ekrāna bloķēšanas opciju, lai turpinātu"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Radās kļūda. Mēģiniet vēlreiz."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pirksta nospieduma ikona"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Autorizācija pēc sejas"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problēma ar autorizāciju pēc sejas"</string> @@ -664,6 +665,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Izmantojiet autorizāciju pēc sejas vai ekrāna bloķēšanas opciju, lai turpinātu"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Radās kļūda. Mēģiniet vēlreiz."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Sejas ikona"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lasīt sinhronizācijas iestatījumus"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ļauj lietotnei lasīt konta sinhronizācijas iestatījumus. Piemēram, šādi var noteikt, vai lietotne Personas ir sinhronizēta ar kontu."</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index b29d49ef8dbe..34a1d29d0810 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Користете го вашиот отпечаток или заклучување екран за да продолжите"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Нешто не е во ред. Обидете се повторно."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатоци"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Отклучување со лик"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем со „Отклучување со лик“"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користете отклучување со лик или заклучување екран за да продолжите"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Нешто не е во ред. Обидете се повторно."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Икона"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"чита поставки за синхронизација"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Овозможува апликацијата да ги чита поставките за синхронизирање на сметка. На пример, така може да се утврди дали апликацијата „Луѓе“ е синхронизирана со сметка."</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index fb7c4daa8e45..68c4f1ce8fbd 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -306,7 +306,7 @@ <string name="permgroupdesc_contacts" msgid="9163927941244182567">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്സസ്സ് ചെയ്യുക"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"ലൊക്കേഷൻ"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ഈ ഉപകരണത്തിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാൻ"</string> - <string name="permgrouplab_calendar" msgid="6426860926123033230">"കലണ്ടർ"</string> + <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ്സ് ചെയ്യുക"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS സന്ദേശങ്ങൾ അയയ്ക്കുകയും കാണുകയും ചെയ്യുക"</string> @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"തുടരാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ഫെയ്സ് അൺലോക്ക്"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ഫെയ്സ് അൺലോക്കുമായി ബന്ധപ്പെട്ട പ്രശ്നം"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"തുടരാൻ നിങ്ങളുടെ മുഖം അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string> <string name="face_icon_content_description" msgid="465030547475916280">"മുഖത്തിന്റെ ഐക്കൺ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string> @@ -2008,7 +2010,7 @@ <string name="app_category_image" msgid="7307840291864213007">"ഫോട്ടോകളും ചിത്രങ്ങളും"</string> <string name="app_category_social" msgid="2278269325488344054">"സാമൂഹിക ആപ്സുകളും ആശയവിനിമയവും"</string> <string name="app_category_news" msgid="1172762719574964544">"വാർത്തകളും മാസികകളും"</string> - <string name="app_category_maps" msgid="6395725487922533156">"മാപ്പുകളും നാവിഗേഷനും"</string> + <string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ഉല്പ്പാദനക്ഷമത"</string> <string name="app_category_accessibility" msgid="6643521607848547683">"ഉപയോഗസഹായി"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ഉപകരണ സ്റ്റോറേജ്"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 424401584b83..f7be6ee95bb5 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Үргэлжлүүлэхийн тулд хурууны хээ эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Алдаа гарлаа. Дахин оролдоно уу."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Хурууны хээний дүрс"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Царайгаар түгжээ тайлах"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Царайгаар түгжээ тайлахтай холбоотой асуудал"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Үргэлжлүүлэхийн тулд царай эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Алдаа гарлаа. Дахин оролдоно уу."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Царайны дүрс тэмдэг"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"синк тохиргоог унших"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Апп нь бүртгэлийн синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 3204189ace12..b18735d835ed 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"पुढे सुरू ठेवण्यासाठी तुमचे फिंगरप्रिंट किंवा स्क्रीन लॉक वापरा"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिंट आयकन"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलॉक"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलॉकसंबंधित समस्या"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"पुढे सुरू ठेवण्यासाठी तुमचा चेहरा किंवा स्क्रीन लॉक वापरा"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string> <string name="face_icon_content_description" msgid="465030547475916280">"चेहरा आयकन"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"सिंक सेटिंग्ज वाचा"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"खात्याच्या सिंक सेटिंग्ज वाचण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांचा अॅप संकालित केला आहे किंवा नाही हे निर्धारित करू शकते."</string> @@ -1016,7 +1018,7 @@ <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"ब्राउझर भौगोलिक स्थान परवानग्या सुधारित करा"</string> <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"ब्राउझरच्या भौगोलिक स्थान परवानग्या सुधारित करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स यादृच्छिक वेबसाइटवर स्थान माहिती पाठविण्यास अनुमती देण्यासाठी याचा वापर करू शकतात."</string> <string name="save_password_message" msgid="2146409467245462965">"ब्राउझरने हा पासवर्ड लक्षात ठेवावा असे तुम्ही इच्छिता?"</string> - <string name="save_password_notnow" msgid="2878327088951240061">"आत्ता नाही"</string> + <string name="save_password_notnow" msgid="2878327088951240061">"आता नको"</string> <string name="save_password_remember" msgid="6490888932657708341">"लक्षात ठेवा"</string> <string name="save_password_never" msgid="6776808375903410659">"कधीही नाही"</string> <string name="open_permission_deny" msgid="5136793905306987251">"तुम्हाला हे पृष्ठ उघडण्याची परवानगी नाही."</string> @@ -2038,7 +2040,7 @@ <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"हे आयटम "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> आणि <xliff:g id="TYPE_2">%3$s</xliff:g> मध्ये अपडेट करायचे का?"</string> <string name="autofill_save_yes" msgid="8035743017382012850">"सेव्ह करा"</string> <string name="autofill_save_no" msgid="9212826374207023544">"नाही, नको"</string> - <string name="autofill_save_notnow" msgid="2853932672029024195">"आता नाही"</string> + <string name="autofill_save_notnow" msgid="2853932672029024195">"आता नको"</string> <string name="autofill_save_never" msgid="6821841919831402526">"कधीही नाही"</string> <string name="autofill_update_yes" msgid="4608662968996874445">"अपडेट करा"</string> <string name="autofill_continue_yes" msgid="7914985605534510385">"पुढे सुरू ठेवा"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 0bf24d7bcc10..2844e1e22f6d 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gunakan cap jari atau kunci skrin anda untuk meneruskan"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Kesilapan telah berlaku. Cuba lagi."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon cap jari"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Buka Kunci Wajah"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Isu dengan Buka Kunci Wajah"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan wajah atau kunci skrin anda untuk meneruskan"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Kesilapan telah berlaku. Cuba lagi."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"membaca tetapan penyegerakan"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Membenarkan apl membaca tetapan segerak untuk akaun. Sebagai contoh, ini boleh menentukan sama ada apl Orang disegerakkan dengan akaun."</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 14409d895099..c2643a56ec68 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ရှေ့ဆက်ရန် သင်၏ လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"လက်ဗွေ သင်္ကေတ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ ဆိုင်ရာ ပြဿနာ"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ရှေ့ဆက်ရန် သင်၏ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string> <string name="face_icon_content_description" msgid="465030547475916280">"မျက်နှာသင်္ကေတ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ထပ်တူပြုအဆင်အပြင်အားဖတ်ခြင်း"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"အပလီကေးရှင်းအား အကောင့်တစ်ခုအတွက် ထပ်တူညီအောင် လုပ်ဆောင်မှု ဆက်တင်အား ကြည့်ခွင့် ပြုပါ။ ဥပမာ People အက်ပ်က အကောင့်တစ်ခုနဲ့ ထပ်တူညီအောင် လုပ်ရန် ဆက်သွယ်ထားမှု ရှိမရှိ သိရှိနိုင်ခြင်း"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index d046447c82c8..0252eb354609 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Bruk fingeravtrykket eller skjermlåsen for å fortsette"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Noe gikk galt. Prøv på nytt."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeravtrykk"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansiktslås"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem med ansiktslås"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Bruk ansikts- eller skjermlåsen for å fortsette"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Noe gikk galt. Prøv på nytt."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ansiktikon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lese synkroniseringsinnstillinger"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lar appen lese synkroniseringsinnstillingene for en konto. For eksempel kan den finne ut om Personer-appen er synkronisert med en konto."</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 6da40726d123..fbf40cfa5fb7 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"जारी राख्न आफ्नो फिंगरप्रिन्ट वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिन्ट आइकन"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलक"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलक सुविधामा अनुहार दर्ता गर्ने क्रममा त्रुटि भयो"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी राख्न आफ्नो फेस वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string> <string name="face_icon_content_description" msgid="465030547475916280">"अनुहारको आइकन"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"समीकरण सेटिङहरू पढ्नुहोस्"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"एपलाई खाताको लागि सिंक सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको एप खातासँग सिंक भएको नभएको निर्धारण गर्न सक्दछ।"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 75857ff45ccb..ef6a441897be 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gebruik je vingerafdruk of schermvergrendeling om door te gaan"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Er is iets misgegaan. Probeer het opnieuw."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ontgrendelen via gezichtsherkenning"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem met Ontgrendelen via gezichtsherkenning"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik je gezicht of schermvergrendeling om door te gaan"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Er is iets misgegaan. Probeer het opnieuw."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Gezichtspictogram"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"synchronisatie-instellingen lezen"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Hiermee kan de app de synchronisatie-instellingen voor een account lezen. Dit kan bijvoorbeeld bepalen of de app Personen wordt gesynchroniseerd met een account."</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 8ba02e606fb6..291c1cc13e88 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ଫେସ୍ ଅନଲକ୍"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ଫେସ୍ ଅନଲକ୍ ସହ ସମସ୍ୟା"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଚେହେରା କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="face_icon_content_description" msgid="465030547475916280">"ଫେସ୍ ଆଇକନ୍"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ସିଙ୍କ ସେଟିଙ୍ଗକୁ ପଢ଼ନ୍ତୁ"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ଏକ ଆକାଉଣ୍ଟ ପାଇଁ ସିଙ୍କ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ୍ଟିକୁ ଅନୁମତି ଦିଏ। ଉଦାହରଣସ୍ୱରୂପ, ଲୋକଙ୍କ ଆପ୍ ଏକ ଆକାଉଣ୍ଟରେ ସିଙ୍କ ହୋଇଛି କି ନାହିଁ ଏହା ଜାଣିପାରେ।"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 209c6a1fb88c..9bd41b43f494 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਤੀਕ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ਫ਼ੇਸ ਅਣਲਾਕ"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ਫ਼ੇਸ ਅਣਲਾਕ ਨਾਲ ਸਮੱਸਿਆ"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਚਿਹਰਾ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="face_icon_content_description" msgid="465030547475916280">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹੋ"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਹ ਪਤਾ ਕਰ ਸਕਦਾ ਹੈ ਕਿ People ਐਪ ਦਾ ਕਿਸੇ ਖਾਤੇ ਨਾਲ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਹੀਂ।"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index b72b0000ce00..2d9160f3e5dc 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aby kontynuować, użyj odcisku palca lub blokady ekranu"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Coś poszło nie tak. Spróbuj ponownie."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odcisku palca"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Rozpoznawanie twarzy"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem z rozpoznawaniem twarzy"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aby kontynuować, użyj rozpoznawania twarzy lub blokady ekranu"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Coś poszło nie tak. Spróbuj ponownie."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona twarzy"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"czytanie ustawień synchronizacji"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Zezwala aplikacji na odczyt ustawień synchronizacji konta. Pozwala to na przykład określić, czy aplikacja Ludzie jest zsynchronizowana z kontem."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 8198ae939e3b..614b8aec5de9 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use sua impressão digital ou o bloqueio de tela para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo deu errado. Tente de novo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo deu errado. Tente de novo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler as configurações de sincronização"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string> @@ -1938,7 +1940,7 @@ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string> <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string> <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificada"</string> - <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string> + <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Abrir"</string> <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Recolher"</string> <string name="expand_action_accessibility" msgid="1947657036871746627">"alternar expansão"</string> <string name="usb_midi_peripheral_name" msgid="490523464968655741">"Porta USB periférica Android"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 5a336ae237e5..64d28ba50104 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilize a impressão digital ou o bloqueio de ecrã para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo correu mal. Tente novamente."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilize o rosto ou o bloqueio de ecrã para continuar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo correu mal. Tente novamente."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ícone de rosto"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler definições de sincronização"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que a app leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a app Pessoas está sincronizada com uma conta."</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 8198ae939e3b..614b8aec5de9 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use sua impressão digital ou o bloqueio de tela para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo deu errado. Tente de novo."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo deu errado. Tente de novo."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler as configurações de sincronização"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string> @@ -1938,7 +1940,7 @@ <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string> <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string> <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificada"</string> - <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string> + <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Abrir"</string> <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Recolher"</string> <string name="expand_action_accessibility" msgid="1947657036871746627">"alternar expansão"</string> <string name="usb_midi_peripheral_name" msgid="490523464968655741">"Porta USB periférica Android"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index ae0a62901a94..9fb501c2c413 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -612,6 +612,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Folosiți amprenta sau blocarea ecranului pentru a continua"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"A apărut o eroare. Încercați din nou."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Deblocare facială"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problemă cu Deblocarea facială"</string> @@ -664,6 +665,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Folosiți-vă chipul sau blocarea ecranului pentru a continua"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"A apărut o eroare. Încercați din nou."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Pictograma chip"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"citire setări sincronizare"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite aplicației să citească setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicația poate determina dacă aplicația Persoane este sincronizată cu un anumit cont."</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 8d3edf1d79e3..c4c69c90b8d0 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Чтобы продолжить, используйте отпечаток пальца или данные для разблокировки экрана."</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Произошла ошибка. Повторите попытку."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок отпечатка пальца"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейсконтроль"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Ошибка фейсконтроля"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Чтобы продолжить, посмотрите на экран или используйте данные для разблокировки."</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Произошла ошибка. Повторите попытку."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Значок лица"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"Просмотр настроек синхронизации"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 132ee6f261c7..fd2e43bed403 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ හෝ තිර අගුල භාවිත කරන්න"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ඇඟිලි සලකුණු නිරූපකය"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"මුහුණෙන් අගුළු හැරීම"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"මුහුණෙන් අගුලු හැරීම සම්බන්ධව ගැටලුවකි"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ඉදිරියට යාමට ඔබගේ මුහුණු හෝ තිර අගුල භාවිත කරන්න"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string> <string name="face_icon_content_description" msgid="465030547475916280">"මුහුණ නිරූපකය"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"සමමුහුර්ත සැකසීම් කියවන්න"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් කියවීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත දැයි මෙයට හඳුනා ගත හැක."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 083c8464957e..c862bc269dcf 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Pokračujte použitím odtlačku prsta alebo zámky obrazovky"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Vyskytla sa chyba. Skúste to znova."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odtlačku prsta"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odomknutie tvárou"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problém s odomknutím tvárou"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte použitím tváre alebo zámky obrazovky"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Vyskytla sa chyba. Skúste to znova."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona tváre"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"čítať nastavenia synchronizácie"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index d632e0c53b6f..9df733fd9be6 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Za nadaljevanje uporabite prstni odtis ali odklepanje s poverilnico."</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Prišlo je do napake. Poskusite znova."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona prstnih odtisov"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odklepanje z obrazom"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Težava z odklepanjem z obrazom"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nadaljevanje uporabite obraz ali odklepanje s poverilnico."</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Prišlo je do napake. Poskusite znova."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona obraza"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"branje nastavitev sinhronizacije"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Aplikaciji omogoča branje nastavitev sinhronizacije za račun. S tem lahko aplikacija na primer ugotovi, ali je aplikacija Ljudje sinhronizirana z računom."</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 239c9f8709da..44c820a8a7f5 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Përdor gjurmën tënde të gishtit ose kyçjen e ekranit për të vazhduar"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Ndodhi një gabim. Provo sërish."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona e gjurmës së gishtit"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Shkyçja me fytyrë"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem me \"Shkyçjen me fytyrë\""</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Përdor fytyrën tënde ose kyçjen e ekranit për të vazhduar"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Ndodhi një gabim. Provo sërish."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ikona e fytyrës"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lexo cilësimet e sinkronizimit"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lejon aplikacionin të lexojë cilësimet e sinkronizimit për një llogari. Për shembull, kjo mund të përcaktojë nëse aplikacioni \"Kontaktet\" është i sinkronizuar me një llogari."</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index cd03394c58d4..911ba91d058e 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -612,6 +612,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Користите отисак прста или закључавање екрана да бисте наставили"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Дошло је до проблема. Пробајте поново."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона отиска прста"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Откључавање лицем"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем са откључавање лицем"</string> @@ -664,6 +665,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користите лице или закључавање екрана да бисте наставили"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Дошло је до проблема. Пробајте поново."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Икона лица"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"читање подешавања синхронизације"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дозвољава апликацији да чита подешавања синхронизације за налог. На пример, овако може да се утврди да ли је апликација Људи синхронизована са налогом."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 940ee568228d..3c388f6cd308 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Fortsätt med hjälp av ditt fingeravtryck eller skärmlåset"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Något gick fel. Försök igen."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon för fingeravtryck"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansiktslås"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem med ansiktslås"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Fortsätt med hjälp av ditt ansikte eller skärmlåset"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Något gick fel. Försök igen."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Ansikte"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"läsa synkroniseringsinställningar"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tillåter att appen läser synkroniseringsinställningarna för ett konto. Detta kan användas till exempel för att avgöra om appen Personer är synkroniserad med ett konto."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index fbee2c3d8ff8..eb679ff6fa1e 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Tumia alama ya kidole au mbinu yako ya kufunga skrini ili uendelee"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Hitilafu fulani imetokea. Jaribu tena."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Aikoni ya alama ya kidole"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Kufungua kwa Uso"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Hitilafu imetokea kwenye kipengele cha Kufungua kwa Uso"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Tumia uso au mbinu yako ya kufunga skrini ili uendelee"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Hitilafu fulani imetokea. Jaribu tena."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Aikoni ya uso"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"kusoma mipangilio ya usawazishaji"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 9565db5c2296..d4060b9819cb 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"தொடர, உங்கள் கைரேகையையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"கைரேகை ஐகான்"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"முகம் காட்டித் திறத்தல்"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"முகம் காட்டித் திறத்தல் அம்சத்தில் சிக்கல்"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"தொடர, உங்கள் முகத்தையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string> <string name="face_icon_content_description" msgid="465030547475916280">"முக ஐகான்"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"ஒத்திசைவு அமைப்புகளைப் படித்தல்"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"கணக்கிற்கான ஒத்திசைவு அமைப்புகளைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. எடுத்துக்காட்டாக, பீப்பிள் ஆப்ஸ் கணக்குடன் ஒத்திசைக்கப்பட்டுள்ளதா என்பதை இது தீர்மானிக்கலாம்."</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 9b51374f5441..365e7c8d9d36 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -361,11 +361,11 @@ <string name="permlab_receiveMms" msgid="4000650116674380275">"వచన మెసేజ్లను (MMS) స్వీకరించడం"</string> <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS మెసేజ్లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. యాప్ మీ డివైజ్కు పంపబడిన మెసేజ్లను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార మెసేజ్లను ఫార్వర్డ్ చేయడం"</string> - <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్లను అందుకుంటే, వాటిని ఫార్వర్డ్ చేసే విధంగా సెల్ ప్రసార మాడ్యూల్కు కట్టుబడి ఉండటానికి యాప్ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం అందుకున్నప్పుడు హానికరమైన యాప్లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string> + <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్లను స్వీకరించినప్పుడు, వాటిని ఫార్వర్డ్ చేయడానికి సెల్ ప్రసార మాడ్యూల్కు కట్టుబడి ఉండేందుకు యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string> <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్ను మేనేజ్ చేయి"</string> <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"మీ పరికరంలో కొనసాగుతున్న కాల్స్ను చూడటానికి అలాగే వాటిని కంట్రోల్ చేయడానికి ఒక యాప్కు అనుమతిస్తోంది."</string> <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార మెసేజ్లను చదవడం"</string> - <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string> + <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string> <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"చందా చేయబడిన ఫీడ్లను చదవడం"</string> <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"ప్రస్తుతం సమకాలీకరించిన ఫీడ్ల గురించి వివరాలను పొందడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_sendSms" msgid="7757368721742014252">"SMS మెసేజ్లను పంపడం మరియు వీక్షించడం"</string> @@ -561,8 +561,8 @@ <string name="permdesc_videoWrite" msgid="6124731210613317051">"మీ వీడియో సేకరణను సవరించడానికి యాప్ని అనుమతిస్తుంది."</string> <string name="permlab_imagesWrite" msgid="1774555086984985578">"మీ ఫోటో సేకరణను ఎడిట్ చేయండి"</string> <string name="permdesc_imagesWrite" msgid="5195054463269193317">"మీ ఫోటో సేకరణను సవరించడానికి యాప్ను అనుమతిస్తుంది."</string> - <string name="permlab_mediaLocation" msgid="7368098373378598066">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string> - <string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> + <string name="permlab_mediaLocation" msgid="7368098373378598066">"మీ మీడియా సేకరణ నుండి లొకేషన్లను చదవండి"</string> + <string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి లొకేషన్లను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"బయోమెట్రిక్స్ను ఉపయోగించండి"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"బయోమెట్రిక్స్ను లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ఇది మీరేనని వెరిఫై చేసుకోండి"</string> @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"కొనసాగించడానికి మీ వేలిముద్ర లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ఫేస్ అన్లాక్"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ఫేస్ అన్లాక్తో సమస్య"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"కొనసాగించడానికి మీ ముఖం లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string> <string name="face_icon_content_description" msgid="465030547475916280">"ముఖ చిహ్నం"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"సింక్ సెట్టింగ్లను చదవగలగడం"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ఖాతా యొక్క సింక్ సెట్టింగ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఉదాహరణకు, వ్యక్తుల యాప్ ఖాతాతో సమకాలీకరించబడాలా లేదా అనే విషయాన్ని ఇది నిశ్చయించవచ్చు."</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 379830a8a189..9c6505efc7da 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"เกิดข้อผิดพลาด ลองอีกครั้ง"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"การปลดล็อกด้วยใบหน้า"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"มีปัญหาเกี่ยวกับฟีเจอร์ปลดล็อกด้วยใบหน้า"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ใช้ใบหน้าหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"เกิดข้อผิดพลาด ลองอีกครั้ง"</string> <string name="face_icon_content_description" msgid="465030547475916280">"ไอคอนใบหน้า"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"อ่านการตั้งค่าการซิงค์"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"อนุญาตให้แอปพลิเคชันอ่านการตั้งค่าการซิงค์ของบัญชี ตัวอย่างเช่น การอนุญาตนี้สามารถระบุได้ว่าแอปพลิเคชัน People ซิงค์กับบัญชีหรือไม่"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 73848a33abb8..c0bb5e3d4f96 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gamitin ang iyong fingerprint o lock ng screen para magpatuloy"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Nagkaproblema. Subukan ulit."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icon ng fingerprint"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Pag-unlock Gamit ang Mukha"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Isyu sa Pag-unlock Gamit ang Mukha"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gamitin ang iyong mukha o lock ng screen para magpatuloy"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Nagkaproblema. Subukan ulit."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"basahin ang mga setting ng sync"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Pinapayagan ang app na basahin ang mga setting ng pag-sync para sa isang account. Halimbawa, matutukoy nito kung naka-sync ang app na Mga Tao sa isang account."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 3325e7e96d5e..d69635988c6e 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Devam etmek için parmak izi veya ekran kilidinizi kullanın"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Bir hata oluştu. Tekrar deneyin."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Parmak izi simgesi"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Yüz Tanıma Kilidi"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Yüz Tanıma Kilidi sorunu"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Devam etmek için yüz veya ekran kilidinizi kullanın"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Bir hata oluştu. Tekrar deneyin."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Yüz simgesi"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"senk. ayarlarını okuma"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Uygulamaya bir hesaba ait senkronizasyon ayarlarını okuma izni verir. Örneğin, bu izne sahip bir uygulama Kişiler uygulamasının bir hesapla senkronize olup olmadığını belirleyebilir."</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 4912be887d9e..cda034f01ea9 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -615,6 +615,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Щоб продовжити, скористайтеся відбитком пальця або даними для розблокування екрана"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Сталася помилка. Повторіть спробу."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок відбитка пальця"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейсконтроль"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Сталася помилка з фейсконтролем"</string> @@ -667,6 +668,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Щоб продовжити, скористайтеся фейсконтролем або даними для розблокування екрана"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Сталася помилка. Повторіть спробу."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Значок обличчя"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"читати налаштування синхронізації"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дозволяє програмі читати налаштування синхронізації для облікового запису, наприклад, визначати, чи програма Люди синхронізується з обліковим записом."</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 2936a080723b..16e4549debfc 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"جاری رکھنے کے لیے اپنے فنگر پرنٹ یا اسکرین لاک کا استعمال کریں"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"کچھ غلط ہو گیا۔ دوبارہ کوشش کریں۔"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"فنگر پرنٹ آئیکن"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"فیس اَنلاک"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"فیس اَنلاک میں مسئلہ"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"جاری رکھنے کے لیے اپنے چہرے یا اسکرین لاک کا استعمال کریں"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"کچھ غلط ہو گیا۔ دوبارہ کوشش کریں۔"</string> <string name="face_icon_content_description" msgid="465030547475916280">"چہرے کا آئیکن"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"مطابقت پذیری کی ترتیبات پڑھیں"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ایپ کو کسی اکاؤنٹ کیلئے مطابقت پذیری کی ترتیبات پڑھنے کی اجازت دیتا ہے۔ مثلا، یہ تعین کرسکتا ہے کہ آیا People ایپ کسی اکاؤنٹ کے ساتھ مطابقت پذیر ہے۔"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index df7d4670dc29..48841acdfa95 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Davom etish uchun barmoq izi yoki ekran qulfidan foydalaning"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Xatolik yuz berdi. Qayta urining."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmoq izi belgisi"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Yuz bilan ochish"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Yuz bilan ochishda muammo bor"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davom etish uchun yuz tekshiruvi yoki ekran qulfidan foydalaning"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Xatolik yuz berdi. Qayta urining."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Yuz belgisi"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"sinx-sh sozlamalarini o‘qish"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ilovaga hisobning sinxronlash sozlamalarini o‘qish uchun ruxsat beradi. Masalan, bu \"Odamlar\" ilovasi hisob bilan sinxronlangan yoki aksini aniqlay oladi."</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 259696dc587c..a7718a00e98d 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Dùng vân tay của bạn hoặc phương thức khóa màn hình để tiếp tục"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Đã xảy ra lỗi. Hãy thử lại."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Biểu tượng vân tay"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Mở khóa bằng khuôn mặt"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Vấn đề với tính năng Mở khóa bằng khuôn mặt"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Dùng khuôn mặt của bạn hoặc phương thức khóa màn hình để tiếp tục"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Đã xảy ra lỗi. Hãy thử lại."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Biểu tượng khuôn mặt"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"đọc cài đặt đồng bộ hóa"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Cho phép ứng dụng đọc cài đặt đồng bộ hóa cho tài khoản. Ví dụ: việc này có thể xác định liệu ứng dụng Mọi người đã được đồng bộ hóa với tài khoản chưa."</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index cc38de217a7b..c43ee058c9e3 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"使用指纹解锁或屏幕锁定凭据验证身份,才能继续操作"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"出了点问题。请重试。"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指纹图标"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"人脸解锁"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"人脸解锁存在问题"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"使用人脸解锁或屏幕锁定凭据验证身份,才能继续操作"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"出了点问题。请重试。"</string> <string name="face_icon_content_description" msgid="465030547475916280">"面孔图标"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"读取同步设置"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允许该应用读取某个帐号的同步设置。例如,此权限可确定“联系人”应用是否与某个帐号同步。"</string> @@ -1216,8 +1218,8 @@ <string name="noApplications" msgid="1186909265235544019">"没有应用可执行此操作。"</string> <string name="aerr_application" msgid="4090916809370389109">"<xliff:g id="APPLICATION">%1$s</xliff:g>已停止运行"</string> <string name="aerr_process" msgid="4268018696970966407">"<xliff:g id="PROCESS">%1$s</xliff:g>已停止运行"</string> - <string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g>屡次停止运行"</string> - <string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g>屡次停止运行"</string> + <string name="aerr_application_repeated" msgid="7804378743218496566">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”屡次停止运行"</string> + <string name="aerr_process_repeated" msgid="1153152413537954974">"“<xliff:g id="PROCESS">%1$s</xliff:g>”屡次停止运行"</string> <string name="aerr_restart" msgid="2789618625210505419">"重新打开应用"</string> <string name="aerr_report" msgid="3095644466849299308">"发送反馈"</string> <string name="aerr_close" msgid="3398336821267021852">"关闭"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index fa2fee5f4083..36b616ae6ece 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"請使用指紋解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"發生錯誤,請再試一次。"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"面孔解鎖"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"「面孔解鎖」功能發生問題"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用面孔解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"發生錯誤,請再試一次。"</string> <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步設定,例如確定「通訊錄」應用程式是否和某個帳戶保持同步。"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 1c02c6bbb285..20fcadfb103e 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"請使用指紋解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"發生錯誤,請再試一次。"</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"人臉解鎖"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"人臉解鎖功能發生問題"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用人臉解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"發生錯誤,請再試一次。"</string> <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index f93b84463874..db19c084316e 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -609,6 +609,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Sebenzisa izigxivizo zakho zomunwe noma ukukhiya isikrini ukuze uqhubeke"</string> <string-array name="fingerprint_error_vendor"> </string-array> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Kunento engahambanga kahle. Zama futhi."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Isithonjana sezigxivizo zeminwe"</string> <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ukuvula ubuso"</string> <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Inkinga Ngokuvula ngobuso"</string> @@ -661,6 +662,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Sebenzisa ubuso bakho noma ukukhiya isikrini ukuze uqhubeke"</string> <string-array name="face_error_vendor"> </string-array> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Kunento engahambanga kahle. Zama futhi."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Isithonjana sobuso"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"funda izilungiselelo zokuvumelanisa"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ivumela uhlelo lokusebenza ukufunda izilungiselelo zokuvumelanisa ze-akhawunti. Isibonelo, lokhu kungacacisa ukuthi noma ngabe uhlelo lokusebenza le-People livumelanisiwe ne-akhawunti."</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index db43b5b31e7e..e1e1201d90df 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -957,6 +957,20 @@ --> <integer name="config_longPressOnPowerBehavior">5</integer> + <!-- The time in milliseconds after which a press on power button is considered "long". --> + <integer name="config_longPressOnPowerDurationMs">500</integer> + + <!-- The possible UI options to be surfaced for configuring long press power on duration + action. Value set in config_longPressOnPowerDurationMs should be one of the available + options to allow users to restore default. --> + <integer-array name="config_longPressOnPowerDurationSettings"> + <item>250</item> + <item>350</item> + <item>500</item> + <item>650</item> + <item>750</item> + </integer-array> + <!-- Whether the setting to change long press on power behaviour from default to assistant (5) is available in Settings. --> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index de7a1175b4a3..2baed4359ff6 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -237,6 +237,9 @@ value is calculated in ConversationLayout#updateActionListPadding() --> <dimen name="notification_actions_padding_start">36dp</dimen> + <!-- The max width of a priority action button when it is collapsed to just the icon. --> + <dimen name="notification_actions_collapsed_priority_width">60dp</dimen> + <!-- The start padding to optionally use (e.g. if there's extra space) for CallStyle notification actions. this = conversation_content_start (80dp) - button inset (4dp) - action padding (12dp) --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a99a22009e3b..b58638cc3ade 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1650,6 +1650,8 @@ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings --> <string-array name="fingerprint_error_vendor"> </string-array> + <!-- Default error message to use when fingerprint_error_vendor does not contain a message. [CHAR LIMIT=NONE] --> + <string name="fingerprint_error_vendor_unknown">Something went wrong. Try again.</string> <!-- Content description which should be used for the fingerprint icon. --> <string name="fingerprint_icon_content_description">Fingerprint icon</string> @@ -1760,6 +1762,8 @@ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings --> <string-array name="face_error_vendor"> </string-array> + <!-- Default error message to use when face_error_vendor does not contain a message. [CHAR LIMIT=NONE] --> + <string name="face_error_vendor_unknown">Something went wrong. Try again.</string> <!-- Content description which should be used for the face icon. [CHAR LIMIT=10] --> <string name="face_icon_content_description">Face icon</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index adb046e76c88..7799b8eb2fb2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -439,6 +439,8 @@ <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" /> <java-symbol type="integer" name="config_immersive_mode_confirmation_panic" /> <java-symbol type="integer" name="config_longPressOnPowerBehavior" /> + <java-symbol type="integer" name="config_longPressOnPowerDurationMs" /> + <java-symbol type="array" name="config_longPressOnPowerDurationSettings" /> <java-symbol type="bool" name="config_longPressOnPowerForAssistantSettingAvailable" /> <java-symbol type="integer" name="config_veryLongPressOnPowerBehavior" /> <java-symbol type="integer" name="config_veryLongPressTimeout" /> @@ -2523,6 +2525,7 @@ <java-symbol type="string" name="fingerprint_error_no_space" /> <java-symbol type="string" name="fingerprint_error_timeout" /> <java-symbol type="array" name="fingerprint_error_vendor" /> + <java-symbol type="string" name="fingerprint_error_vendor_unknown" /> <java-symbol type="string" name="fingerprint_acquired_partial" /> <java-symbol type="string" name="fingerprint_acquired_insufficient" /> <java-symbol type="string" name="fingerprint_acquired_imager_dirty" /> @@ -2562,6 +2565,7 @@ <java-symbol type="string" name="face_error_no_space" /> <java-symbol type="string" name="face_error_timeout" /> <java-symbol type="array" name="face_error_vendor" /> + <java-symbol type="string" name="face_error_vendor_unknown" /> <java-symbol type="string" name="face_error_canceled" /> <java-symbol type="string" name="face_error_user_canceled" /> <java-symbol type="string" name="face_error_lockout" /> @@ -3183,6 +3187,7 @@ <java-symbol type="id" name="notification_action_list_margin_target" /> <java-symbol type="dimen" name="notification_actions_padding_start"/> + <java-symbol type="dimen" name="notification_actions_collapsed_priority_width"/> <java-symbol type="dimen" name="notification_action_disabled_alpha" /> <java-symbol type="id" name="tag_margin_end_when_icon_visible" /> <java-symbol type="id" name="tag_margin_end_when_icon_gone" /> diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index cd07d464ee65..34c1763b3286 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -16,9 +16,11 @@ package android.app; -import static androidx.core.graphics.ColorUtils.calculateContrast; +import static android.app.Notification.Builder.ensureColorSpanContrast; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsAtLeast; +import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsWithinRange; import static com.google.common.truth.Truth.assertThat; @@ -35,6 +37,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.content.LocusId; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -42,12 +45,21 @@ import android.graphics.drawable.Icon; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.text.style.TextAppearanceSpan; import android.widget.RemoteViews; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.R; +import com.android.internal.util.ContrastColorUtil; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -334,6 +346,163 @@ public class NotificationTest { } @Test + public void testBuilder_getFullLengthSpanColor_returnsNullForString() { + assertThat(Notification.Builder.getFullLengthSpanColor("String")).isNull(); + } + + @Test + public void testBuilder_getFullLengthSpanColor_returnsNullWithPartialSpan() { + CharSequence text = new SpannableStringBuilder() + .append("text with ") + .append("some red", new ForegroundColorSpan(Color.RED), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isNull(); + } + + @Test + public void testBuilder_getFullLengthSpanColor_worksWithSingleSpan() { + CharSequence text = new SpannableStringBuilder() + .append("text that is all red", new ForegroundColorSpan(Color.RED), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.RED); + } + + @Test + public void testBuilder_getFullLengthSpanColor_worksWithFullAndPartialSpans() { + Spannable text = new SpannableString("blue text with yellow and green"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(Color.BLUE); + } + + @Test + public void testBuilder_getFullLengthSpanColor_worksWithTextAppearance() { + Spannable text = new SpannableString("title text with yellow and green"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, + R.style.TextAppearance_DeviceDefault_Notification_Title); + int expectedTextColor = textAppearanceSpan.getTextColor().getDefaultColor(); + text.setSpan(textAppearanceSpan, 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(expectedTextColor); + } + + @Test + public void testBuilder_ensureColorSpanContrast_removesAllFullLengthColorSpans() { + Spannable text = new SpannableString("blue text with yellow and green"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext, + R.style.TextAppearance_DeviceDefault_Notification_Title); + assertThat(taSpan.getTextColor()).isNotNull(); // it must be set to prove it is cleared. + text.setSpan(taSpan, 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable result = (Spannable) ensureColorSpanContrast(text, Color.BLACK); + Object[] spans = result.getSpans(0, result.length(), Object.class); + assertThat(spans).hasLength(3); + + assertThat(result.getSpanStart(spans[0])).isEqualTo(15); + assertThat(result.getSpanEnd(spans[0])).isEqualTo(21); + assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW); + + assertThat(result.getSpanStart(spans[1])).isEqualTo(0); + assertThat(result.getSpanEnd(spans[1])).isEqualTo(31); + assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span + assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily()); + assertThat(((TextAppearanceSpan) spans[1]).getTextColor()).isNull(); + + assertThat(result.getSpanStart(spans[2])).isEqualTo(26); + assertThat(result.getSpanEnd(spans[2])).isEqualTo(31); + assertThat(((ForegroundColorSpan) spans[2]).getForegroundColor()).isEqualTo(Color.GREEN); + } + + @Test + public void testBuilder_ensureColorSpanContrast_partialLength_adjusted() { + int background = 0xFFFF0101; // Slightly lighter red + CharSequence text = new SpannableStringBuilder() + .append("text with ") + .append("some red", new ForegroundColorSpan(Color.RED), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + CharSequence result = ensureColorSpanContrast(text, background); + + // ensure the span has been updated to have > 1.3:1 contrast ratio with fill color + Object[] spans = ((Spannable) result).getSpans(0, result.length(), Object.class); + assertThat(spans).hasLength(1); + int foregroundColor = ((ForegroundColorSpan) spans[0]).getForegroundColor(); + assertContrastIsWithinRange(foregroundColor, background, 3, 3.2); + } + + @Test + public void testBuilder_ensureColorSpanContrast_worksWithComplexInput() { + Spannable text = new SpannableString("blue text with yellow and green and cyan"); + text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + // cyan TextAppearanceSpan + TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext, + R.style.TextAppearance_DeviceDefault_Notification_Title); + taSpan = new TextAppearanceSpan(taSpan.getFamily(), taSpan.getTextStyle(), + taSpan.getTextSize(), ColorStateList.valueOf(Color.CYAN), null); + text.setSpan(taSpan, 36, 40, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable result = (Spannable) ensureColorSpanContrast(text, Color.GRAY); + Object[] spans = result.getSpans(0, result.length(), Object.class); + assertThat(spans).hasLength(3); + + assertThat(result.getSpanStart(spans[0])).isEqualTo(15); + assertThat(result.getSpanEnd(spans[0])).isEqualTo(21); + assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW); + + assertThat(result.getSpanStart(spans[1])).isEqualTo(36); + assertThat(result.getSpanEnd(spans[1])).isEqualTo(40); + assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span + assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily()); + ColorStateList newCyanList = ((TextAppearanceSpan) spans[1]).getTextColor(); + assertThat(newCyanList).isNotNull(); + assertContrastIsWithinRange(newCyanList.getDefaultColor(), Color.GRAY, 3, 3.2); + + assertThat(result.getSpanStart(spans[2])).isEqualTo(26); + assertThat(result.getSpanEnd(spans[2])).isEqualTo(31); + int newGreen = ((ForegroundColorSpan) spans[2]).getForegroundColor(); + assertThat(newGreen).isNotEqualTo(Color.GREEN); + assertContrastIsWithinRange(newGreen, Color.GRAY, 3, 3.2); + } + + @Test + public void testBuilder_ensureButtonFillContrast_adjustsDarker() { + int background = Color.LTGRAY; + int foreground = Color.LTGRAY; + int result = Notification.Builder.ensureButtonFillContrast(foreground, background); + assertContrastIsWithinRange(result, background, 1.3, 1.5); + assertThat(ContrastColorUtil.calculateLuminance(result)) + .isLessThan(ContrastColorUtil.calculateLuminance(background)); + } + + @Test + public void testBuilder_ensureButtonFillContrast_adjustsLighter() { + int background = Color.DKGRAY; + int foreground = Color.DKGRAY; + int result = Notification.Builder.ensureButtonFillContrast(foreground, background); + assertContrastIsWithinRange(result, background, 1.3, 1.5); + assertThat(ContrastColorUtil.calculateLuminance(result)) + .isGreaterThan(ContrastColorUtil.calculateLuminance(background)); + } + + @Test public void testColors_ensureColors_dayMode_producesValidPalette() { Notification.Colors c = new Notification.Colors(); boolean colorized = false; @@ -399,6 +568,8 @@ public class NotificationTest { assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor()); assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor()); assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor()); + assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor()); + assertEquals(cDay.getOnAccentTextColor(), cNight.getOnAccentTextColor()); assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor()); assertEquals(cDay.getContrastColor(), cNight.getContrastColor()); assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha()); @@ -413,30 +584,26 @@ public class NotificationTest { assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); + assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID); + assertThat(c.getOnAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID); assertThat(c.getRippleAlpha()).isAtLeast(0x00); assertThat(c.getRippleAlpha()).isAtMost(0xff); - // Assert that various colors have sufficient contrast + // Assert that various colors have sufficient contrast with the background assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5); assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5); - // This accent color is only used for emphasized buttons + // These colors are only used for emphasized buttons; they do not need contrast assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1); - } + assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1); - private void assertContrastIsAtLeast(int foreground, int background, double minContrast) { - try { - assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast); - } catch (AssertionError e) { - throw new AssertionError( - String.format("Insufficient contrast: foreground=#%08x background=#%08x", - foreground, background), e); - } + // The text that is used within the accent color DOES need to have contrast + assertContrastIsAtLeast(c.getOnAccentTextColor(), c.getTertiaryAccentColor(), 4.5); } private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor, diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java index 22f6ec0b24b1..701e6194d4ee 100644 --- a/core/tests/coretests/src/android/graphics/FontListParserTest.java +++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java @@ -27,6 +27,7 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.fail; +import android.graphics.fonts.FontCustomizationParser; import android.graphics.fonts.FontStyle; import android.os.LocaleList; import android.text.FontConfig; @@ -46,6 +47,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) @@ -318,6 +320,52 @@ public final class FontListParserTest { } } + @Test + public void alias() throws Exception { + String xml = "<?xml version='1.0' encoding='UTF-8'?>" + + "<familyset>" + + " <family name='sans-serif'>" + + " <font>test.ttf</font>" + + " </family>" + + " <family name='custom-family'>" + + " <font>missing.ttf</font>" + + " </family>" + + " <alias name='custom-alias' to='sans-serif'/>" + + "</familyset>"; + FontConfig config = readFamilies(xml, true /* include non-existing font files */); + List<FontConfig.Alias> aliases = config.getAliases(); + assertThat(aliases.size()).isEqualTo(1); + assertThat(aliases.get(0).getName()).isEqualTo("custom-alias"); + assertThat(aliases.get(0).getOriginal()).isEqualTo("sans-serif"); + } + + @Test + public void dropped_FamilyAlias() throws Exception { + String xml = "<?xml version='1.0' encoding='UTF-8'?>" + + "<familyset>" + + " <family name='sans-serif'>" + + " <font>test.ttf</font>" + + " </family>" + + " <family name='custom-family'>" + + " <font>missing.ttf</font>" + + " </family>" + + " <alias name='custom-alias' to='custom-family'/>" + + "</familyset>"; + FontConfig config = readFamilies(xml, false /* exclude not existing file */); + assertThat(config.getAliases()).isEmpty(); + } + + private FontConfig readFamilies(String xml, boolean allowNonExisting) + throws IOException, XmlPullParserException { + ByteArrayInputStream buffer = new ByteArrayInputStream( + xml.getBytes(StandardCharsets.UTF_8)); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(buffer, "UTF-8"); + parser.nextTag(); + return FontListParser.readFamilies(parser, "", new FontCustomizationParser.Result(), null, + 0L /* last modified date */, 0 /* config version */, allowNonExisting); + } + private FontConfig.FontFamily readFamily(String xml) throws IOException, XmlPullParserException { ByteArrayInputStream buffer = new ByteArrayInputStream( diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index dfc9013e3c05..149f58f0a69b 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -32,6 +32,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -121,6 +122,46 @@ public class DisplayManagerGlobalTest { Mockito.verifyZeroInteractions(mListener); } + @Test + public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreNoOtherListeners() + throws RemoteException { + mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks(); + Mockito.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(ALL_DISPLAY_EVENTS)); + + mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks(); + Mockito.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L)); + + } + + @Test + public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreListeners() + throws RemoteException { + mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); + InOrder inOrder = Mockito.inOrder(mDisplayManager); + + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + + mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks(); + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), + eq(ALL_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + + mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks(); + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); + + mDisplayManagerGlobal.unregisterDisplayListener(mListener); + inOrder.verify(mDisplayManager) + .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L)); + + } + private void waitForHandler() { mHandler.runWithScissors(() -> { }, 0); } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java index 464412f17722..b7dc1c59c90c 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java @@ -23,6 +23,8 @@ import android.app.ActivityManager; import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.Uid.Sensor; +import android.os.Process; +import android.os.UserHandle; import android.os.WorkSource; import android.util.SparseLongArray; import android.view.Display; @@ -53,6 +55,8 @@ import java.util.Map; public class BatteryStatsNoteTest extends TestCase { private static final int UID = 10500; + private static final int ISOLATED_APP_ID = Process.FIRST_ISOLATED_UID + 23; + private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID); private static final WorkSource WS = new WorkSource(UID); /** @@ -114,6 +118,88 @@ public class BatteryStatsNoteTest extends TestCase { assertEquals(120_000, bgTime); } + /** + * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid. + */ + @SmallTest + public void testNoteStartWakeLocked_isolatedUid() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + + int pid = 10; + String name = "name"; + String historyName = "historyName"; + + WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain(); + isolatedWorkChain.addNode(ISOLATED_UID, name); + + // Map ISOLATED_UID to UID. + bi.addIsolatedUidLocked(ISOLATED_UID, UID); + + bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); + bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL, false); + + clocks.realtime = clocks.uptime = 100; + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + + clocks.realtime = clocks.uptime = 220; + bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL); + + // ISOLATED_UID wakelock time should be attributed to UID. + BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID) + .getAggregatedPartialWakelockTimer(); + long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + assertEquals(220_000, actualTime); + assertEquals(120_000, bgTime); + } + + /** + * Test BatteryStatsImpl.Uid.noteStartWakeLocked for an isolated uid, with a race where the + * isolated uid is removed from batterystats before the wakelock has been stopped. + */ + @SmallTest + public void testNoteStartWakeLocked_isolatedUidRace() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + + int pid = 10; + String name = "name"; + String historyName = "historyName"; + + WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain(); + isolatedWorkChain.addNode(ISOLATED_UID, name); + + // Map ISOLATED_UID to UID. + bi.addIsolatedUidLocked(ISOLATED_UID, UID); + + bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); + bi.noteStartWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL, false); + + clocks.realtime = clocks.uptime = 100; + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + + clocks.realtime = clocks.uptime = 150; + bi.maybeRemoveIsolatedUidLocked(ISOLATED_UID, clocks.realtime, clocks.uptime); + + clocks.realtime = clocks.uptime = 220; + bi.noteStopWakeLocked(ISOLATED_UID, pid, isolatedWorkChain, name, historyName, + WAKE_TYPE_PARTIAL); + + // ISOLATED_UID wakelock time should be attributed to UID. + BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID) + .getAggregatedPartialWakelockTimer(); + long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); + assertEquals(220_000, actualTime); + assertEquals(120_000, bgTime); + } + /** * Test BatteryStatsImpl.noteUidProcessStateLocked. diff --git a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java new file mode 100644 index 000000000000..cfe660c77817 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.internal.util; + +import static androidx.core.graphics.ColorUtils.calculateContrast; + +import static com.google.common.truth.Truth.assertThat; + +import android.graphics.Color; + +import androidx.test.filters.SmallTest; + +import junit.framework.TestCase; + +public class ContrastColorUtilTest extends TestCase { + + @SmallTest + public void testEnsureTextContrastAgainstDark() { + int darkBg = 0xFF35302A; + + int blueContrastColor = ContrastColorUtil.ensureTextContrast(Color.BLUE, darkBg, true); + assertContrastIsWithinRange(blueContrastColor, darkBg, 4.5, 4.75); + + int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, darkBg, true); + assertContrastIsWithinRange(redContrastColor, darkBg, 4.5, 4.75); + + final int darkGreen = 0xff008800; + int greenContrastColor = ContrastColorUtil.ensureTextContrast(darkGreen, darkBg, true); + assertContrastIsWithinRange(greenContrastColor, darkBg, 4.5, 4.75); + + int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.DKGRAY, darkBg, true); + assertContrastIsWithinRange(grayContrastColor, darkBg, 4.5, 4.75); + + int selfContrastColor = ContrastColorUtil.ensureTextContrast(darkBg, darkBg, true); + assertContrastIsWithinRange(selfContrastColor, darkBg, 4.5, 4.75); + } + + @SmallTest + public void testEnsureTextContrastAgainstLight() { + int lightBg = 0xFFFFF8F2; + + final int lightBlue = 0xff8888ff; + int blueContrastColor = ContrastColorUtil.ensureTextContrast(lightBlue, lightBg, false); + assertContrastIsWithinRange(blueContrastColor, lightBg, 4.5, 4.75); + + int redContrastColor = ContrastColorUtil.ensureTextContrast(Color.RED, lightBg, false); + assertContrastIsWithinRange(redContrastColor, lightBg, 4.5, 4.75); + + int greenContrastColor = ContrastColorUtil.ensureTextContrast(Color.GREEN, lightBg, false); + assertContrastIsWithinRange(greenContrastColor, lightBg, 4.5, 4.75); + + int grayContrastColor = ContrastColorUtil.ensureTextContrast(Color.LTGRAY, lightBg, false); + assertContrastIsWithinRange(grayContrastColor, lightBg, 4.5, 4.75); + + int selfContrastColor = ContrastColorUtil.ensureTextContrast(lightBg, lightBg, false); + assertContrastIsWithinRange(selfContrastColor, lightBg, 4.5, 4.75); + } + + public static void assertContrastIsWithinRange(int foreground, int background, + double minContrast, double maxContrast) { + assertContrastIsAtLeast(foreground, background, minContrast); + assertContrastIsAtMost(foreground, background, maxContrast); + } + + public static void assertContrastIsAtLeast(int foreground, int background, double minContrast) { + try { + assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast); + } catch (AssertionError e) { + throw new AssertionError( + String.format("Insufficient contrast: foreground=#%08x background=#%08x", + foreground, background), e); + } + } + + public static void assertContrastIsAtMost(int foreground, int background, double maxContrast) { + try { + assertThat(calculateContrast(foreground, background)).isAtMost(maxContrast); + } catch (AssertionError e) { + throw new AssertionError( + String.format("Excessive contrast: foreground=#%08x background=#%08x", + foreground, background), e); + } + } + +} diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 93a336e7a408..96b33259e739 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -25,6 +25,7 @@ import android.graphics.fonts.FontVariationAxis; import android.os.Build; import android.os.LocaleList; import android.text.FontConfig; +import android.util.ArraySet; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; @@ -37,6 +38,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -120,7 +122,23 @@ public class FontListParser { } } - private static FontConfig readFamilies( + /** + * Parses the familyset tag in font.xml + * @param parser a XML pull parser + * @param fontDir A system font directory, e.g. "/system/fonts" + * @param customization A OEM font customization + * @param updatableFontMap A map of updated font files + * @param lastModifiedDate A date that the system font is updated. + * @param configVersion A version of system font config. + * @param allowNonExistingFile true if allowing non-existing font files during parsing fonts.xml + * @return result of fonts.xml + * + * @throws XmlPullParserException + * @throws IOException + * + * @hide + */ + public static FontConfig readFamilies( @NonNull XmlPullParser parser, @NonNull String fontDir, @NonNull FontCustomizationParser.Result customization, @@ -159,7 +177,24 @@ public class FontListParser { } families.addAll(oemNamedFamilies.values()); - return new FontConfig(families, aliases, lastModifiedDate, configVersion); + + // Filters aliases that point to non-existing families. + Set<String> namedFamilies = new ArraySet<>(); + for (int i = 0; i < families.size(); ++i) { + String name = families.get(i).getName(); + if (name != null) { + namedFamilies.add(name); + } + } + List<FontConfig.Alias> filtered = new ArrayList<>(); + for (int i = 0; i < aliases.size(); ++i) { + FontConfig.Alias alias = aliases.get(i); + if (namedFamilies.contains(alias.getOriginal())) { + filtered.add(alias); + } + } + + return new FontConfig(families, filtered, lastModifiedDate, configVersion); } private static boolean keepReading(XmlPullParser parser) diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java index f3cfcf18dec1..67358c4f3255 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -579,7 +579,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { // // Note: mNamespace == KeyProperties.NAMESPACE_APPLICATION implies that the target domain // is Domain.APP and Domain.SELINUX is the target domain otherwise. - if (alias != descriptor.alias + if (!alias.equals(descriptor.alias) || descriptor.domain != targetDomain || (descriptor.domain == Domain.SELINUX && descriptor.nspace != targetNamespace)) { throw new KeyStoreException("Can only replace keys with same alias: " + alias diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index c0df06f2954f..ac97c8f80617 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -576,20 +576,17 @@ public class BubbleStackView extends FrameLayout mBubbleContainer.setActiveController(mStackAnimationController); hideFlyoutImmediate(); - if (!mPositioner.showingInTaskbar()) { - // Also, save the magnetized stack so we can dispatch touch events to it. - mMagnetizedObject = mStackAnimationController.getMagnetizedStack( - mMagneticTarget); - mMagnetizedObject.setMagnetListener(mStackMagnetListener); - } else { + if (mPositioner.showingInTaskbar()) { // In taskbar, the stack isn't draggable so we shouldn't dispatch touch events. mMagnetizedObject = null; + } else { + // Save the magnetized stack so we can dispatch touch events to it. + mMagnetizedObject = mStackAnimationController.getMagnetizedStack(); + mMagnetizedObject.clearAllTargets(); + mMagnetizedObject.addTarget(mMagneticTarget); + mMagnetizedObject.setMagnetListener(mStackMagnetListener); } - // Also, save the magnetized stack so we can dispatch touch events to it. - mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget); - mMagnetizedObject.setMagnetListener(mStackMagnetListener); - mIsDraggingStack = true; // Cancel animations to make the stack temporarily invisible, since we're now @@ -881,7 +878,6 @@ public class BubbleStackView extends FrameLayout mRelativeStackPositionBeforeRotation = null; } - setUpDismissView(); if (mIsExpanded) { // Re-draw bubble row and pointer for new orientation. beforeExpandedViewAnimation(); @@ -1043,10 +1039,9 @@ public class BubbleStackView extends FrameLayout contentResolver, "bubble_dismiss_radius", mBubbleSize * 2 /* default */); // Save the MagneticTarget instance for the newly set up view - we'll add this to the - // MagnetizedObjects. + // MagnetizedObjects when the dismiss view gets shown. mMagneticTarget = new MagnetizedObject.MagneticTarget( mDismissView.getCircle(), dismissRadius); - mBubbleContainer.bringToFront(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java index 0802fb59a008..636e1452aa9b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java @@ -1024,11 +1024,9 @@ public class StackAnimationController extends } /** - * Returns the {@link MagnetizedObject} instance for the bubble stack, with the provided - * {@link MagnetizedObject.MagneticTarget} added as a target. + * Returns the {@link MagnetizedObject} instance for the bubble stack. */ - public MagnetizedObject<StackAnimationController> getMagnetizedStack( - MagnetizedObject.MagneticTarget target) { + public MagnetizedObject<StackAnimationController> getMagnetizedStack() { if (mMagnetizedStack == null) { mMagnetizedStack = new MagnetizedObject<StackAnimationController>( mLayout.getContext(), @@ -1053,7 +1051,6 @@ public class StackAnimationController extends loc[1] = (int) mStackPosition.y; } }; - mMagnetizedStack.addTarget(target); mMagnetizedStack.setHapticsEnabled(true); mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt index 9f6dd1f27b62..9e012598554b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt @@ -303,6 +303,13 @@ abstract class MagnetizedObject<T : Any>( } /** + * Removes all associated targets from this object. + */ + fun clearAllTargets() { + associatedTargets.clear() + } + + /** * Provide this method with all motion events that move the magnetized object. If the * location of the motion events moves within the magnetic field of a target, or indicate a * fling-to-target gesture, this method will return true and you should not move the object diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java index d3274706631b..9e1c61aac868 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java @@ -23,6 +23,7 @@ import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.view.ContextThemeWrapper; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.animation.LinearInterpolator; @@ -33,7 +34,6 @@ import android.window.DisplayAreaOrganizer; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import androidx.appcompat.view.ContextThemeWrapper; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index f58c6b173af9..81dd60d715e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -32,6 +32,7 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; import android.view.SurfaceControl; @@ -44,7 +45,6 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.appcompat.view.ContextThemeWrapper; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java index a5e96d14dde6..20021ebea834 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Binder; +import android.util.Log; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; @@ -45,7 +46,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; class SizeCompatUILayout { private static final String TAG = "SizeCompatUILayout"; - private final SyncTransactionQueue mSyncQueue; + final SyncTransactionQueue mSyncQueue; private final SizeCompatUIController.SizeCompatUICallback mCallback; private Context mContext; private Configuration mTaskConfig; @@ -306,6 +307,10 @@ class SizeCompatUILayout { private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) { mSyncQueue.runInSync(t -> { + if (!leash.isValid()) { + Log.w(TAG, "The leash has been released."); + return; + } t.setPosition(leash, positionX, positionY); // The size compat UI should be the topmost child of the Task in case there can be more // than one children. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java index f634c4586e39..82f69c3e2985 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java @@ -110,7 +110,8 @@ class SizeCompatUIWindowManager extends WindowlessWindowManager { } if (mLeash != null) { - new SurfaceControl.Transaction().remove(mLeash).apply(); + final SurfaceControl leash = mLeash; + mLayout.mSyncQueue.runInSync(t -> t.remove(leash)); mLeash = null; } } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 0c422df65881..b348a6ecaae4 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -341,6 +341,7 @@ std::optional<RenderNode::SnapshotResult> RenderNode::updateSnapshotIfRequired( sk_sp<SkImage> snapshot = layerSurface->makeImageSnapshot(); const auto subset = SkIRect::MakeWH(properties().getWidth(), properties().getHeight()); + uint32_t layerSurfaceGenerationId = layerSurface->generationID(); // If we don't have an ImageFilter just return the snapshot if (imageFilter == nullptr) { mSnapshotResult.snapshot = snapshot; @@ -348,9 +349,10 @@ std::optional<RenderNode::SnapshotResult> RenderNode::updateSnapshotIfRequired( mSnapshotResult.outOffset = SkIPoint::Make(0.0f, 0.0f); mImageFilterClipBounds = clipBounds; mTargetImageFilter = nullptr; - } else if (mSnapshotResult.snapshot == nullptr || - imageFilter != mTargetImageFilter.get() || - mImageFilterClipBounds != clipBounds) { + mTargetImageFilterLayerSurfaceGenerationId = 0; + } else if (mSnapshotResult.snapshot == nullptr || imageFilter != mTargetImageFilter.get() || + mImageFilterClipBounds != clipBounds || + mTargetImageFilterLayerSurfaceGenerationId != layerSurfaceGenerationId) { // Otherwise create a new snapshot with the given filter and snapshot mSnapshotResult.snapshot = snapshot->makeWithFilter(context, @@ -361,6 +363,7 @@ std::optional<RenderNode::SnapshotResult> RenderNode::updateSnapshotIfRequired( &mSnapshotResult.outOffset); mTargetImageFilter = sk_ref_sp(imageFilter); mImageFilterClipBounds = clipBounds; + mTargetImageFilterLayerSurfaceGenerationId = layerSurfaceGenerationId; } return mSnapshotResult; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 45a4f6c9c70d..da0476259b97 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -396,6 +396,7 @@ private: * SkImageFilter used to create the mSnapshotResult */ sk_sp<SkImageFilter> mTargetImageFilter; + uint32_t mTargetImageFilterLayerSurfaceGenerationId = 0; /** * Clip bounds used to create the mSnapshotResult diff --git a/mms/OWNERS b/mms/OWNERS index 7f05a2a24d6e..2e419c1e529c 100644 --- a/mms/OWNERS +++ b/mms/OWNERS @@ -9,10 +9,10 @@ jackyu@google.com jminjie@google.com satk@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS index 0d23f053499c..a2352e20f841 100644 --- a/packages/CarrierDefaultApp/OWNERS +++ b/packages/CarrierDefaultApp/OWNERS @@ -8,11 +8,11 @@ jackyu@google.com jminjie@google.com satk@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index 48cdf1647d86..197b7b2b0eaf 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -31,7 +31,7 @@ android:directBootAware="true"> <receiver android:name=".TemporaryFileManager" - android:exported="true"> + android:exported="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> @@ -76,7 +76,7 @@ <receiver android:name=".InstallEventReceiver" android:permission="android.permission.INSTALL_PACKAGES" - android:exported="true"> + android:exported="false"> <intent-filter android:priority="1"> <action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" /> </intent-filter> @@ -106,14 +106,14 @@ <receiver android:name=".UninstallEventReceiver" android:permission="android.permission.INSTALL_PACKAGES" - android:exported="true"> + android:exported="false"> <intent-filter android:priority="1"> <action android:name="com.android.packageinstaller.ACTION_UNINSTALL_COMMIT" /> </intent-filter> </receiver> <receiver android:name=".PackageInstalledReceiver" - android:exported="true"> + android:exported="false"> <intent-filter android:priority="1"> <action android:name="android.intent.action.PACKAGE_ADDED" /> <data android:scheme="package" /> diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING index 5d7b9bb36f75..cef9014ec229 100644 --- a/packages/PackageInstaller/TEST_MAPPING +++ b/packages/PackageInstaller/TEST_MAPPING @@ -19,6 +19,9 @@ }, { "name": "CtsPackageUninstallTestCases" + }, + { + "name": "PackageInstallerTests" } ] -}
\ No newline at end of file +} diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 9876539678ae..67bc8496b9ed 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -245,9 +245,9 @@ <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Tillad, at startindlæseren låses op"</string> <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Vil du tillade OEM-oplåsning?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ADVARSEL! Funktioner, der beskytter enheden, fungerer ikke på denne enhed, når denne indstilling er aktiveret."</string> - <string name="mock_location_app" msgid="6269380172542248304">"Vælg app til falsk lokation"</string> - <string name="mock_location_app_not_set" msgid="6972032787262831155">"Der er ikke angivet nogen app til falsk lokation"</string> - <string name="mock_location_app_set" msgid="4706722469342913843">"App til falsk lokation: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app" msgid="6269380172542248304">"Vælg app til falsk placering"</string> + <string name="mock_location_app_not_set" msgid="6972032787262831155">"Der er ikke angivet nogen app til falsk placering"</string> + <string name="mock_location_app_set" msgid="4706722469342913843">"App til falsk placering: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="6829757985772659599">"Netværk"</string> <string name="wifi_display_certification" msgid="1805579519992520381">"Certificering af trådløs skærm"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivér detaljeret Wi-Fi-logføring"</string> @@ -295,8 +295,8 @@ <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"Vælg logbuffere, der skal gemmes permanent på enheden"</string> <string name="select_usb_configuration_title" msgid="6339801314922294586">"Vælg USB-konfiguration"</string> <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"Vælg USB-konfiguration"</string> - <string name="allow_mock_location" msgid="2102650981552527884">"Imiterede lokationer"</string> - <string name="allow_mock_location_summary" msgid="179780881081354579">"Tillad imiterede lokationer"</string> + <string name="allow_mock_location" msgid="2102650981552527884">"Imiterede placeringer"</string> + <string name="allow_mock_location_summary" msgid="179780881081354579">"Tillad imiterede placeringer"</string> <string name="debug_view_attributes" msgid="3539609843984208216">"Aktivér visning af attributinspektion"</string> <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Hold altid mobildata aktiveret, selv når Wi-Fi er aktiveret (for at skifte hurtigt mellem netværk)."</string> <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Brug hardwareacceleration ved netdeling, hvis det er muligt"</string> @@ -332,7 +332,7 @@ <string name="debug_monitoring_category" msgid="1597387133765424994">"Overvågning"</string> <string name="strict_mode" msgid="889864762140862437">"Striks tilstand aktiveret"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Blink med skærmen, når apps foretager handlinger på hovedtråd"</string> - <string name="pointer_location" msgid="7516929526199520173">"Markørens lokation"</string> + <string name="pointer_location" msgid="7516929526199520173">"Markørens placering"</string> <string name="pointer_location_summary" msgid="957120116989798464">"Skærmoverlejringen viser de aktuelle berøringsdata"</string> <string name="show_touches" msgid="8437666942161289025">"Vis tryk"</string> <string name="show_touches_summary" msgid="3692861665994502193">"Vis visuel feedback ved tryk"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index cbf92af607d2..2fbe33e88056 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -47,7 +47,7 @@ <string name="private_dns_broken" msgid="1984159464346556931">"Жеке DNS серверіне кіру мүмкін емес."</string> <string name="wifi_limited_connection" msgid="1184778285475204682">"Шектеулі байланыс"</string> <string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернетпен байланыс жоқ"</string> - <string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Аккаунтқа кіру керек"</string> + <string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Есептік жазбаға кіру керек"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"Кіру нүктесі уақытша бос емес"</string> <string name="connected_via_carrier" msgid="1968057009076191514">"%1$s арқылы қосылды"</string> <string name="available_via_carrier" msgid="465598683092718294">"%1$s арқылы қолжетімді"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 11e443be927b..631cb3b9b628 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -552,7 +552,7 @@ <string name="user_setup_dialog_message" msgid="269931619868102841">"तो वापरकर्ता डिव्हाइसजवळ आहे आणि त्याचे स्थान सेट करण्यासाठी उपलब्ध आहे याची खात्री करा"</string> <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"आता प्रोफाईल सेट करायचा?"</string> <string name="user_setup_button_setup_now" msgid="1708269547187760639">"आता सेट करा"</string> - <string name="user_setup_button_setup_later" msgid="8712980133555493516">"आता नको"</string> + <string name="user_setup_button_setup_later" msgid="8712980133555493516">"आत्ता नाही"</string> <string name="user_add_user_type_title" msgid="551279664052914497">"जोडा"</string> <string name="user_new_user_name" msgid="60979820612818840">"नवीन वापरकर्ता"</string> <string name="user_new_profile_name" msgid="2405500423304678841">"नवीन प्रोफाईल"</string> diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml index 35cc015616bf..c062007056d5 100644 --- a/packages/SettingsLib/res/values-sk/arrays.xml +++ b/packages/SettingsLib/res/values-sk/arrays.xml @@ -59,7 +59,7 @@ <item msgid="6421717003037072581">"Vždy používať kontrolu HDCP"</item> </string-array> <string-array name="bt_hci_snoop_log_entries"> - <item msgid="695678520785580527">"Vypnuté"</item> + <item msgid="695678520785580527">"Deaktivované"</item> <item msgid="6336372935919715515">"Aktivované filtrované"</item> <item msgid="2779123106632690576">"Aktivované"</item> </string-array> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 5da56d1325e4..44f067c3ccd6 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -295,8 +295,8 @@ <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"పరికరంలో నిరంతరం నిల్వ చేయాల్సిన లాగ్ బఫర్లను ఎంచుకోండి"</string> <string name="select_usb_configuration_title" msgid="6339801314922294586">"USB కాన్ఫిగరేషన్ని ఎంచుకోండి"</string> <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"USB కాన్ఫిగరేషన్ని ఎంచుకోండి"</string> - <string name="allow_mock_location" msgid="2102650981552527884">"డమ్మీ లొకేషన్లను అనుమతించండి"</string> - <string name="allow_mock_location_summary" msgid="179780881081354579">"డమ్మీ లొకేషన్లను అనుమతించండి"</string> + <string name="allow_mock_location" msgid="2102650981552527884">"అనుకృత స్థానాలను అనుమతించు"</string> + <string name="allow_mock_location_summary" msgid="179780881081354579">"అనుకృత స్థానాలను అనుమతించు"</string> <string name="debug_view_attributes" msgid="3539609843984208216">"వీక్షణ అట్రిబ్యూట్ పర్యవేక్షణను ఎనేబుల్ చేయి"</string> <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"ఎల్లప్పుడూ మొబైల్ డేటాను యాక్టివ్గా ఉంచు, Wi‑Fi యాక్టివ్గా ఉన్నా కూడా (వేగవంతమైన నెట్వర్క్ మార్పు కోసం)."</string> <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"అందుబాటులో ఉంటే టెథెరింగ్ హార్డ్వేర్ వేగవృద్ధిని ఉపయోగించండి"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 72fa25fc7a3a..bf0dc7bce5f9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -157,7 +157,6 @@ public class WifiStatusTracker { private Network mDefaultNetwork = null; private NetworkCapabilities mDefaultNetworkCapabilities = null; private final Runnable mCallback; - private final boolean mSupportMergedUi; private WifiInfo mWifiInfo; public boolean enabled; @@ -181,7 +180,6 @@ public class WifiStatusTracker { mNetworkScoreManager = networkScoreManager; mConnectivityManager = connectivityManager; mCallback = callback; - mSupportMergedUi = false; } public void setListening(boolean listening) { @@ -223,10 +221,8 @@ public class WifiStatusTracker { } else { ssid = getValidSsid(mWifiInfo); } - if (mSupportMergedUi) { - isCarrierMerged = mWifiInfo.isCarrierMerged(); - subId = mWifiInfo.getSubscriptionId(); - } + isCarrierMerged = mWifiInfo.isCarrierMerged(); + subId = mWifiInfo.getSubscriptionId(); updateRssi(mWifiInfo.getRssi()); maybeRequestNetworkScore(); } @@ -255,10 +251,8 @@ public class WifiStatusTracker { } else { ssid = getValidSsid(mWifiInfo); } - if (mSupportMergedUi) { - isCarrierMerged = mWifiInfo.isCarrierMerged(); - subId = mWifiInfo.getSubscriptionId(); - } + isCarrierMerged = mWifiInfo.isCarrierMerged(); + subId = mWifiInfo.getSubscriptionId(); updateRssi(mWifiInfo.getRssi()); maybeRequestNetworkScore(); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index 61006156d8aa..56454e975370 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -20,10 +20,13 @@ import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_ import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason; import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiInfo; +import android.os.Bundle; import android.os.SystemClock; import androidx.annotation.VisibleForTesting; @@ -36,6 +39,23 @@ public class WifiUtils { private static final int INVALID_RSSI = -127; + /** + * The intent action shows network details settings to allow configuration of Wi-Fi. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: The calling package should put the chosen + * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into + * the {@link #KEY_CHOSEN_WIFIENTRY_KEY}. + * <p> + * Output: Nothing. + */ + public static final String ACTION_WIFI_DETAILS_SETTINGS = + "android.settings.WIFI_DETAILS_SETTINGS"; + public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; + public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; + static final int[] WIFI_PIE = { com.android.internal.R.drawable.ic_wifi_signal_0, com.android.internal.R.drawable.ic_wifi_signal_1, @@ -275,7 +295,42 @@ public class WifiUtils { return noInternet ? NO_INTERNET_WIFI_PIE[level] : WIFI_PIE[level]; } + /** + * Wrapper the {@link #getInternetIconResource} for testing compatibility. + */ + public static class InternetIconInjector { + + protected final Context mContext; + + public InternetIconInjector(Context context) { + mContext = context; + } + + /** + * Returns the Internet icon for a given RSSI level. + * + * @param noInternet True if a connected Wi-Fi network cannot access the Internet + * @param level The number of bars to show (0-4) + */ + public Drawable getIcon(boolean noInternet, int level) { + return mContext.getDrawable(WifiUtils.getInternetIconResource(level, noInternet)); + } + } + public static boolean isMeteredOverridden(WifiConfiguration config) { return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE; } + + /** + * Returns the Intent for Wi-Fi network details settings. + * + * @param key The Wi-Fi entry key + */ + public static Intent getWifiDetailsSettingsIntent(String key) { + final Intent intent = new Intent(ACTION_WIFI_DETAILS_SETTINGS); + final Bundle bundle = new Bundle(); + bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key); + intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle); + return intent; + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java index 89960cba2bf5..7c2b904fc576 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java @@ -20,9 +20,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.Intent; import android.net.NetworkKey; import android.net.RssiCurve; import android.net.ScoredNetwork; @@ -36,6 +39,8 @@ import android.os.SystemClock; import android.text.format.DateUtils; import android.util.ArraySet; +import androidx.test.core.app.ApplicationProvider; + import com.android.settingslib.R; import org.junit.Before; @@ -44,7 +49,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.Set; @@ -69,7 +73,7 @@ public class WifiUtilsTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(ApplicationProvider.getApplicationContext()); } @Test @@ -148,6 +152,32 @@ public class WifiUtilsTest { assertThat(WifiUtils.isMeteredOverridden(mWifiConfig)).isTrue(); } + @Test + public void getWifiDetailsSettingsIntent_returnsCorrectValues() { + final String key = "test_key"; + + final Intent intent = WifiUtils.getWifiDetailsSettingsIntent(key); + + assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DETAILS_SETTINGS); + final Bundle bundle = intent.getBundleExtra(WifiUtils.EXTRA_SHOW_FRAGMENT_ARGUMENTS); + assertThat(bundle.getString(WifiUtils.KEY_CHOSEN_WIFIENTRY_KEY)).isEqualTo(key); + } + + @Test + public void testInternetIconInjector_getIcon_returnsCorrectValues() { + WifiUtils.InternetIconInjector iconInjector = new WifiUtils.InternetIconInjector(mContext); + + for (int level = 0; level <= 4; level++) { + iconInjector.getIcon(false /* noInternet */, level); + verify(mContext).getDrawable( + WifiUtils.getInternetIconResource(level, false /* noInternet */)); + + iconInjector.getIcon(true /* noInternet */, level); + verify(mContext).getDrawable( + WifiUtils.getInternetIconResource(level, true /* noInternet */)); + } + } + private static ArrayList<ScanResult> buildScanResultCache() { ArrayList<ScanResult> scanResults = new ArrayList<>(); for (int i = 0; i < 5; i++) { diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java index eb8196176034..a46d28b273e5 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java @@ -76,5 +76,6 @@ public class GlobalSettings { Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED, Settings.Global.DEVICE_CONFIG_SYNC_DISABLED, Settings.Global.POWER_BUTTON_LONG_PRESS, + Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 60226084c70d..96f127b6a611 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -101,6 +101,7 @@ public class SecureSettings { Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, Settings.Secure.QS_TILES, + Settings.Secure.QS_AUTO_ADDED_TILES, Settings.Secure.CONTROLS_ENABLED, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, Settings.Secure.DOZE_ENABLED, @@ -118,7 +119,6 @@ public class SecureSettings { Settings.Secure.VR_DISPLAY_MODE, Settings.Secure.NOTIFICATION_BADGING, Settings.Secure.NOTIFICATION_DISMISS_RTL, - Settings.Secure.QS_AUTO_ADDED_TILES, Settings.Secure.SCREENSAVER_ENABLED, Settings.Secure.SCREENSAVER_COMPONENTS, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index 5220a04d73e6..84c5febcb5a2 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -20,6 +20,7 @@ import static android.media.AudioFormat.SURROUND_SOUND_ENCODING; import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR; import static android.provider.settings.validators.SettingsValidators.PERCENTAGE_INTEGER_VALIDATOR; import static android.view.Display.HdrCapabilities.HDR_TYPES; @@ -140,6 +141,7 @@ public class GlobalSettingsValidators { /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT)); VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, NONE_NEGATIVE_LONG_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index c57786888e8d..6cfcb51239a3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -72,8 +72,9 @@ public class SettingsHelper { * {@hide} */ private static final ArraySet<String> sBroadcastOnRestore; + private static final ArraySet<String> sBroadcastOnRestoreSystemUI; static { - sBroadcastOnRestore = new ArraySet<String>(4); + sBroadcastOnRestore = new ArraySet<String>(9); sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); @@ -83,6 +84,9 @@ public class SettingsHelper { sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME); sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED); sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + sBroadcastOnRestoreSystemUI = new ArraySet<String>(2); + sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES); + sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_AUTO_ADDED_TILES); } private interface SettingsLookup { @@ -133,6 +137,7 @@ public class SettingsHelper { // Will we need a post-restore broadcast for this element? String oldValue = null; boolean sendBroadcast = false; + boolean sendBroadcastSystemUI = false; final SettingsLookup table; if (destination.equals(Settings.Secure.CONTENT_URI)) { @@ -143,10 +148,12 @@ public class SettingsHelper { table = sGlobalLookup; } - if (sBroadcastOnRestore.contains(name)) { + sendBroadcast = sBroadcastOnRestore.contains(name); + sendBroadcastSystemUI = sBroadcastOnRestoreSystemUI.contains(name); + + if (sendBroadcast || sendBroadcastSystemUI) { // TODO: http://b/22388012 oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM); - sendBroadcast = true; } try { @@ -193,18 +200,28 @@ public class SettingsHelper { } catch (Exception e) { // If we fail to apply the setting, by definition nothing happened sendBroadcast = false; + sendBroadcastSystemUI = false; } finally { // If this was an element of interest, send the "we just restored it" // broadcast with the historical value now that the new value has // been committed and observers kicked off. - if (sendBroadcast) { + if (sendBroadcast || sendBroadcastSystemUI) { Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED) - .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) .putExtra(Intent.EXTRA_SETTING_NAME, name) .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value) .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue) .putExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, restoredFromSdkInt); - context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); + + if (sendBroadcast) { + intent.setPackage("android"); + context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); + } + if (sendBroadcastSystemUI) { + intent.setPackage( + context.getString(com.android.internal.R.string.config_systemUi)); + context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null); + } } } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 073b4d00653d..4ac19386db0a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -763,9 +763,6 @@ class SettingsProtoDumpUtil { Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES); dumpSetting(s, p, - Settings.Global.ANGLE_ALLOWLIST, - GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST); - dumpSetting(s, p, Settings.Global.ANGLE_EGL_FEATURES, GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES); dumpSetting(s, p, @@ -1195,6 +1192,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.POWER_MANAGER_CONSTANTS, GlobalSettingsProto.POWER_MANAGER_CONSTANTS); + dumpSetting(s, p, + Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, + GlobalSettingsProto.POWER_BUTTON_LONG_PRESS_DURATION_MS); final long prepaidSetupToken = p.start(GlobalSettingsProto.PREPAID_SETUP); dumpSetting(s, p, @@ -1476,6 +1476,9 @@ class SettingsProtoDumpUtil { Settings.Global.USE_OPEN_WIFI_PACKAGE, GlobalSettingsProto.USE_OPEN_WIFI_PACKAGE); dumpSetting(s, p, + Settings.Global.UWB_ENABLED, + GlobalSettingsProto.UWB_ENABLED); + dumpSetting(s, p, Settings.Global.VT_IMS_ENABLED, GlobalSettingsProto.VT_IMS_ENABLED); dumpSetting(s, p, diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 3297937e3e75..7db73c697ea7 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -509,7 +509,6 @@ public class SettingsBackupTest { Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE, Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, - Settings.Global.ANGLE_ALLOWLIST, Settings.Global.ANGLE_EGL_FEATURES, Settings.Global.UPDATABLE_DRIVER_ALL_APPS, Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS, @@ -519,6 +518,7 @@ public class SettingsBackupTest { Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST, Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST, Settings.Global.UPDATABLE_DRIVER_SPHAL_LIBRARIES, + Settings.Global.UWB_ENABLED, Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, Settings.Global.GPU_DEBUG_LAYER_APP, Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, diff --git a/packages/SystemUI/res-keyguard/values/donottranslate.xml b/packages/SystemUI/res-keyguard/values/donottranslate.xml index a4d0ff7269a2..1934457b4bc6 100644 --- a/packages/SystemUI/res-keyguard/values/donottranslate.xml +++ b/packages/SystemUI/res-keyguard/values/donottranslate.xml @@ -21,6 +21,9 @@ <!-- Skeleton string format for displaying the date when an alarm is set. --> <string name="abbrev_wday_month_day_no_year_alarm">EEEMMMd</string> + <!-- Skeleton string format for displaying the date shorter. --> + <string name="abbrev_month_day_no_year">MMMd</string> + <!-- Skeleton string format for displaying the time in 12-hour format. --> <string name="clock_12hr_format">hm</string> diff --git a/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml new file mode 100644 index 000000000000..13133cb451e4 --- /dev/null +++ b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Copy of progress_indeterminate_horizontal_rect2 in frameworks/base/core/res --> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="2000" + android:propertyXName="translateX" + android:pathData="M -197.60001,0 c 14.28182,0 85.07782,0 135.54689,0 c 54.26191,0 90.42461,0 168.24331,0 c 144.72154,0 316.40982,0 316.40982,0 " + android:interpolator="@interpolator/progress_indeterminate_horizontal_rect2_translatex_copy" + android:repeatCount="infinite" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_state_off.xml b/packages/SystemUI/res/color/settingslib_state_off.xml new file mode 100644 index 000000000000..e8218259087d --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_state_off.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_state_on.xml b/packages/SystemUI/res/color/settingslib_state_on.xml new file mode 100644 index 000000000000..6d2133c5bacf --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_state_on.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentPrimary"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_track_off.xml b/packages/SystemUI/res/color/settingslib_track_off.xml new file mode 100644 index 000000000000..21d1dccbf900 --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_track_off.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentSecondary"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/settingslib_track_on.xml b/packages/SystemUI/res/color/settingslib_track_on.xml new file mode 100644 index 000000000000..ba7848a5d23e --- /dev/null +++ b/packages/SystemUI/res/color/settingslib_track_on.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentPrimaryVariant"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_arrow_forward.xml b/packages/SystemUI/res/drawable/ic_arrow_forward.xml new file mode 100644 index 000000000000..438e4c70dc71 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_arrow_forward.xml @@ -0,0 +1,26 @@ +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:autoMirrored="true" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="@android:color/black" + android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml new file mode 100644 index 000000000000..2c34060ccd61 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?android:attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2H9V6zM18,20H6V10h12V20zM12,17c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2C10,16.1 10.9,17 12,17z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_media_home_devices.xml b/packages/SystemUI/res/drawable/ic_media_home_devices.xml new file mode 100644 index 000000000000..886c64d9bf02 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_media_home_devices.xml @@ -0,0 +1,16 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M20,4H4c-1.1,0 -2,0.9 -2,2v11c0,1.1 0.9,2 2,2h4v2h3v-4H4V6h16v1h2V6c0,-1.1 -0.9,-2 -2,-2z"/> + <path + android:fillColor="@android:color/white" + android:pathData="M17.5,16.5m-2.33,0a2.33,2.33 0,1 1,4.66 0a2.33,2.33 0,1 1,-4.66 0"/> + <path + android:fillColor="@android:color/white" + android:pathData="M21,8h-7c-0.55,0 -1,0.45 -1,1v11c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1L22,9c0,-0.55 -0.45,-1 -1,-1zM17.5,9c0.83,0 1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5 -1.5,-0.67 -1.5,-1.5 0.67,-1.5 1.5,-1.5zM17.5,20c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml new file mode 100644 index 000000000000..ac4c43bd35b9 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml @@ -0,0 +1,29 @@ +<!-- + Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml new file mode 100644 index 000000000000..f38a36804bc8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#FF000000" + android:pathData="M2,22l16,0l0,-2l-11,0l13,-13l0,1l2,0l0,-6z" + android:strokeAlpha="0.3" + android:fillAlpha="0.3"/> + <path + android:fillColor="#FF000000" + android:pathData="M20,10h2v8h-2z"/> + <path + android:fillColor="#FF000000" + android:pathData="M20,20h2v2h-2z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_background.xml b/packages/SystemUI/res/drawable/internet_dialog_background.xml new file mode 100644 index 000000000000..3ceb0f6ac06a --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<inset xmlns:android="http://schemas.android.com/apk/res/android"> + <shape android:shape="rectangle"> + <corners android:radius="8dp" /> + <solid android:color="?android:attr/colorBackground" /> + </shape> +</inset> diff --git a/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml new file mode 100644 index 000000000000..50267fda0b25 --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:shape="rectangle"> + <stroke + android:color="?androidprv:attr/colorAccentPrimaryVariant" + android:width="1dp"/> + <corners android:radius="20dp"/> + <padding + android:left="8dp" + android:right="8dp" + android:top="4dp" + android:bottom="4dp" /> + <solid android:color="@android:color/transparent" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml new file mode 100644 index 000000000000..14672ef3dcfe --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android"> + <shape android:shape="rectangle"> + <corners + android:topLeftRadius="@dimen/internet_dialog_corner_radius" + android:topRightRadius="@dimen/internet_dialog_corner_radius" + android:bottomLeftRadius="@dimen/internet_dialog_corner_radius" + android:bottomRightRadius="@dimen/internet_dialog_corner_radius"/> + <solid android:color="?android:attr/colorBackground" /> + </shape> +</inset> diff --git a/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml new file mode 100644 index 000000000000..95209f8eb8ab --- /dev/null +++ b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Copy of progress_indeterminate_horizontal_material_trimmed in frameworks/base/core/res --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" > + <target + android:name="rect_grp" + android:animation="@anim/progress_indeterminate_horizontal_rect" /> +</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml new file mode 100644 index 000000000000..088e82bb4260 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?android:attr/colorControlHighlight"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/settingslib_state_off_color"/> + <corners android:radius="@dimen/settingslib_switch_bar_radius"/> + </shape> + </item> +</ripple> diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml new file mode 100644 index 000000000000..250188b892f4 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?android:attr/colorControlHighlight"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/settingslib_state_on_color"/> + <corners android:radius="@dimen/settingslib_switch_bar_radius"/> + </shape> + </item> +</ripple> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml new file mode 100644 index 000000000000..b41762f7908e --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:top="@dimen/settingslib_switch_thumb_margin" + android:left="@dimen/settingslib_switch_thumb_margin" + android:right="@dimen/settingslib_switch_thumb_margin" + android:bottom="@dimen/settingslib_switch_thumb_margin"> + <shape android:shape="oval"> + <size + android:height="@dimen/settingslib_switch_thumb_size" + android:width="@dimen/settingslib_switch_thumb_size"/> + <solid + android:color="@color/settingslib_thumb_off_color" + android:alpha="?android:attr/disabledAlpha"/> + </shape> + </item> +</layer-list> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_off.xml b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml new file mode 100644 index 000000000000..87d4aeaac84f --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:top="@dimen/settingslib_switch_thumb_margin" + android:bottom="@dimen/settingslib_switch_thumb_margin"> + <shape android:shape="oval"> + <size + android:height="@dimen/settingslib_switch_thumb_size" + android:width="@dimen/settingslib_switch_thumb_size"/> + <solid android:color="@color/settingslib_thumb_off_color"/> + </shape> + </item> +</layer-list> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml new file mode 100644 index 000000000000..5566ea3f62fc --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:top="@dimen/settingslib_switch_thumb_margin" + android:bottom="@dimen/settingslib_switch_thumb_margin"> + <shape android:shape="oval"> + <size + android:height="@dimen/settingslib_switch_thumb_size" + android:width="@dimen/settingslib_switch_thumb_size"/> + <solid android:color="@color/settingslib_state_on_color"/> + </shape> + </item> +</layer-list> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml new file mode 100644 index 000000000000..06bb779b91ef --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/settingslib_thumb_on" android:state_checked="true"/> + <item android:drawable="@drawable/settingslib_thumb_off" android:state_checked="false"/> + <item android:drawable="@drawable/settingslib_thumb_disabled" android:state_enabled="false"/> +</selector> diff --git a/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml new file mode 100644 index 000000000000..15dfcb70e25e --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + android:width="@dimen/settingslib_switch_track_width" + android:height="@dimen/settingslib_switch_track_height"> + <solid + android:color="@color/settingslib_track_off_color" + android:alpha="?android:attr/disabledAlpha"/> + <corners android:radius="@dimen/settingslib_switch_track_radius"/> +</shape> diff --git a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml new file mode 100644 index 000000000000..3a09284d10a0 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + android:width="@dimen/settingslib_switch_track_width" + android:height="@dimen/settingslib_switch_track_height"> + <padding android:left="@dimen/settingslib_switch_thumb_margin" + android:right="@dimen/settingslib_switch_thumb_margin"/> + <solid android:color="@color/settingslib_track_off_color"/> + <corners android:radius="@dimen/settingslib_switch_track_radius"/> +</shape> diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml new file mode 100644 index 000000000000..1d9dacd6c0f9 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + android:width="@dimen/settingslib_switch_track_width" + android:height="@dimen/settingslib_switch_track_height"> + <padding android:left="@dimen/settingslib_switch_thumb_margin" + android:right="@dimen/settingslib_switch_thumb_margin"/> + <solid android:color="@color/settingslib_track_on_color"/> + <corners android:radius="@dimen/settingslib_switch_track_radius"/> +</shape> diff --git a/packages/SystemUI/res/drawable/settingslib_track_selector.xml b/packages/SystemUI/res/drawable/settingslib_track_selector.xml new file mode 100644 index 000000000000..a38c3b4241a3 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_selector.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/settingslib_track_on_background" android:state_checked="true"/> + <item android:drawable="@drawable/settingslib_track_off_background" android:state_checked="false"/> + <item android:drawable="@drawable/settingslib_track_disabled_background" android:state_enabled="false"/> +</selector> diff --git a/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml new file mode 100644 index 000000000000..aec204f45aa7 --- /dev/null +++ b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:height="10dp" + android:width="340dp" + android:viewportHeight="10" + android:viewportWidth="340" > + <group + android:name="progress_group" + android:translateX="180" + android:translateY="5" > + <path + android:name="background_track" + android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z" + android:fillColor="?androidprv:attr/colorSurfaceVariant"/> + <group + android:name="rect_grp" + android:translateX="-197.60001" + android:scaleX="0.5" > + <path + android:name="rect" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?androidprv:attr/colorAccentPrimaryVariant" /> + </group> + </group> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/global_actions_toast.xml b/packages/SystemUI/res/layout/global_actions_toast.xml new file mode 100644 index 000000000000..1f0899623ddf --- /dev/null +++ b/packages/SystemUI/res/layout/global_actions_toast.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center|bottom" + android:gravity="center" + android:layout_marginBottom="@dimen/global_actions_info_margin" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintWidth_max="382dp" + android:layout_weight="0" + android:background="@drawable/global_actions_lite_background" + android:theme="@style/Theme.SystemUI.QuickSettings" + android:paddingTop="14dp" + android:paddingBottom="14dp" + android:paddingStart="20dp" + android:paddingEnd="20dp" + android:orientation="horizontal"> + <TextView + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textSize="14sp" + android:textColor="?android:attr/textColorSecondary" + android:text="@string/global_action_smart_lock_disabled" /> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml index e4a96947aa6a..6a9254cad8f4 100644 --- a/packages/SystemUI/res/layout/global_screenshot_static.xml +++ b/packages/SystemUI/res/layout/global_screenshot_static.xml @@ -36,7 +36,6 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal" - android:layout_marginBottom="@dimen/screenshot_action_container_offset_y" android:paddingEnd="@dimen/screenshot_action_container_padding_right" android:paddingVertical="@dimen/screenshot_action_container_padding_vertical" android:elevation="1dp" diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml new file mode 100644 index 000000000000..b841419c1c75 --- /dev/null +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -0,0 +1,373 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/internet_connectivity_dialog" + android:layout_width="@dimen/internet_dialog_list_max_width" + android:layout_height="@dimen/internet_dialog_list_max_height" + android:background="@drawable/internet_dialog_rounded_top_corner_background" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Widget.SliceView.Panel" + android:gravity="center_vertical|center_horizontal" + android:layout_marginTop="24dp" + android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin" + android:orientation="vertical"> + + <TextView + android:id="@+id/internet_dialog_title" + android:gravity="center_vertical|center_horizontal" + android:layout_width="wrap_content" + android:layout_height="32dp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="google-sans" + android:textSize="24sp"/> + + <TextView + android:id="@+id/internet_dialog_subtitle" + android:gravity="center_vertical|center_horizontal" + android:layout_width="wrap_content" + android:layout_height="20dp" + android:layout_marginTop="4dp" + android:ellipsize="end" + android:maxLines="1" + android:fontFamily="google-sans" + android:textSize="14sp"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin" + android:orientation="vertical"> + + <View + android:id="@+id/divider" + android:layout_gravity="center_vertical|center_horizontal" + android:layout_width="340dp" + android:layout_height="4dp" + android:background="?androidprv:attr/colorSurfaceVariant"/> + + <ProgressBar + android:id="@+id/wifi_searching_progress" + android:indeterminate="true" + android:layout_width="340dp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:visibility="gone" + style="@style/TrimmedHorizontalProgressBar"/> + </LinearLayout> + + <androidx.core.widget.NestedScrollView + android:id="@+id/scroll_view" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout + android:id="@+id/scroll_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <LinearLayout + android:id="@+id/internet_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/mobile_network_layout" + android:layout_width="match_parent" + android:layout_height="88dp" + android:clickable="true" + android:focusable="true" + android:background="?android:attr/selectableItemBackground" + android:layout_gravity="center_vertical|start" + android:orientation="horizontal" + android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:paddingStart="22dp" + android:paddingEnd="22dp"> + + <FrameLayout + android:layout_width="24dp" + android:layout_height="24dp" + android:clickable="false" + android:layout_gravity="center_vertical|start"> + <ImageView + android:id="@+id/signal_icon" + android:autoMirrored="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + </FrameLayout> + + <LinearLayout + android:layout_weight="1" + android:id="@+id/mobile_network_list" + android:orientation="vertical" + android:clickable="false" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="start|center_vertical"> + <TextView + android:id="@+id/mobile_title" + android:textDirection="locale" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:layout_marginEnd="7dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|start" + android:ellipsize="end" + android:textColor="?android:attr/textColorPrimary" + android:textSize="16sp" + android:fontFamily="google-sans"/> + <TextView + android:id="@+id/mobile_summary" + android:textDirection="locale" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:layout_marginEnd="34dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|start" + android:ellipsize="end" + android:textColor="?android:attr/textColorTertiary" + android:textSize="14sp" + android:fontFamily="google-sans"/> + </LinearLayout> + + <FrameLayout + android:layout_width="@dimen/settingslib_switch_track_width" + android:layout_height="48dp" + android:layout_gravity="end|center_vertical"> + <Switch + android:id="@+id/mobile_toggle" + android:switchMinWidth="@dimen/settingslib_switch_track_width" + android:layout_gravity="center" + android:layout_width="@dimen/settingslib_switch_track_width" + android:layout_height="@dimen/settingslib_switch_track_height" + android:track="@drawable/settingslib_track_selector" + android:thumb="@drawable/settingslib_thumb_selector" + android:theme="@style/MainSwitch.Settingslib"/> + </FrameLayout> + + </LinearLayout> + + <LinearLayout + android:id="@+id/turn_on_wifi_layout" + android:layout_width="match_parent" + android:layout_height="72dp" + android:clickable="true" + android:focusable="true" + android:background="?android:attr/selectableItemBackground" + android:gravity="center" + android:orientation="horizontal" + android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:paddingStart="22dp" + android:paddingEnd="22dp"> + + <FrameLayout + android:layout_weight="1" + android:orientation="vertical" + android:clickable="false" + android:layout_width="wrap_content" + android:layout_height="match_parent"> + <TextView + android:id="@+id/wifi_toggle_title" + android:text="@string/turn_on_wifi" + android:textDirection="locale" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="start|center_vertical" + android:textColor="?android:attr/textColorPrimary" + android:textSize="16sp" + android:fontFamily="google-sans"/> + </FrameLayout> + + <FrameLayout + android:layout_width="@dimen/settingslib_switch_track_width" + android:layout_height="48dp" + android:layout_marginTop="10dp" + android:layout_marginBottom="10dp"> + <Switch + android:id="@+id/wifi_toggle" + android:switchMinWidth="@dimen/settingslib_switch_track_width" + android:layout_gravity="center" + android:layout_width="@dimen/settingslib_switch_track_width" + android:layout_height="@dimen/settingslib_switch_track_height" + android:track="@drawable/settingslib_track_selector" + android:thumb="@drawable/settingslib_thumb_selector" + android:theme="@style/MainSwitch.Settingslib"/> + </FrameLayout> + + </LinearLayout> + + <LinearLayout + android:id="@+id/wifi_connected_layout" + android:layout_width="match_parent" + android:layout_height="72dp" + android:layout_gravity="center_vertical|start" + android:clickable="true" + android:focusable="true" + android:visibility="gone" + android:background="?android:attr/selectableItemBackground" + android:orientation="horizontal" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin" + android:paddingStart="20dp" + android:paddingEnd="24dp"> + + <FrameLayout + android:layout_width="24dp" + android:layout_height="24dp" + android:clickable="false" + android:layout_gravity="center_vertical|start"> + <ImageView + android:id="@+id/wifi_connected_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + </FrameLayout> + + <LinearLayout + android:id="@+id/wifi_connected_list" + android:orientation="vertical" + android:clickable="false" + android:layout_width="wrap_content" + android:layout_height="72dp" + android:layout_marginEnd="30dp" + android:layout_weight="1" + android:gravity="start|center_vertical"> + <TextView + android:id="@+id/wifi_connected_title" + android:textDirection="locale" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:ellipsize="end" + android:textColor="?android:attr/textColorPrimary" + android:textSize="14sp" + android:fontFamily="google-sans"/> + <TextView + android:id="@+id/wifi_connected_summary" + android:textDirection="locale" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" + android:ellipsize="end" + android:textColor="?android:attr/textColorTertiary" + android:textSize="14sp" + android:fontFamily="google-sans"/> + </LinearLayout> + + <FrameLayout + android:layout_width="24dp" + android:layout_height="match_parent" + android:clickable="false" + android:layout_gravity="end|center_vertical" + android:gravity="center"> + <ImageView + android:id="@+id/wifi_settings_icon" + android:src="@drawable/ic_settings_24dp" + android:layout_width="24dp" + android:layout_gravity="end|center_vertical" + android:layout_height="wrap_content"/> + </FrameLayout> + + </LinearLayout> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/wifi_list_layout" + android:scrollbars="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:overScrollMode="never" + android:nestedScrollingEnabled="false"/> + + </LinearLayout> + + <LinearLayout + android:id="@+id/see_all_layout" + android:layout_width="match_parent" + android:layout_height="64dp" + android:clickable="true" + android:focusable="true" + android:background="?android:attr/selectableItemBackground" + android:gravity="center_vertical|center_horizontal" + android:orientation="horizontal" + android:paddingStart="22dp" + android:paddingEnd="22dp"> + + <FrameLayout + android:layout_width="24dp" + android:layout_height="24dp" + android:clickable="false" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> + <ImageView + android:id="@+id/arrow_forward" + android:src="@drawable/ic_arrow_forward" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + </FrameLayout> + + <FrameLayout + android:orientation="vertical" + android:clickable="false" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> + <TextView + android:text="@string/see_all_networks" + android:textDirection="locale" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="start|center_vertical" + android:textColor="?android:attr/textColorPrimary" + android:textSize="14sp" + android:fontFamily="google-sans"/> + </FrameLayout> + + </LinearLayout> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="48dp" + android:layout_marginBottom="40dp"> + <Button + style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored" + android:id="@+id/done" + android:layout_width="67dp" + android:layout_height="36dp" + android:layout_marginEnd="24dp" + android:layout_gravity="end|center_vertical" + android:background="@drawable/internet_dialog_footer_background" + android:textColor="?android:attr/textColorPrimary" + android:text="@string/inline_done_button" + android:textSize="14sp" + android:fontFamily="google-sans"/> + </FrameLayout> + </LinearLayout> + </androidx.core.widget.NestedScrollView> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml new file mode 100644 index 000000000000..05352c507e7e --- /dev/null +++ b/packages/SystemUI/res/layout/internet_list_item.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/internet_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/wifi_list" + android:layout_width="match_parent" + android:layout_height="72dp" + android:layout_gravity="center_vertical|start" + android:clickable="true" + android:focusable="true" + android:background="?android:attr/selectableItemBackground" + android:orientation="horizontal" + android:paddingStart="20dp" + android:paddingEnd="40dp"> + <FrameLayout + android:layout_width="24dp" + android:layout_height="24dp" + android:clickable="false" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> + <ImageView + android:id="@+id/wifi_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + </FrameLayout> + + <LinearLayout + android:id="@+id/wifi_network_layout" + android:orientation="vertical" + android:clickable="false" + android:layout_width="wrap_content" + android:layout_height="72dp" + android:layout_weight="1" + android:gravity="start|center_vertical" + android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> + <TextView + android:id="@+id/wifi_title" + android:textDirection="locale" + android:layout_width="wrap_content" + android:layout_height="20dp" + android:gravity="start|center_vertical" + android:ellipsize="end" + android:textColor="?android:attr/textColorPrimary" + android:textSize="14sp" + android:fontFamily="google-sans" + android:layout_marginEnd="18dp"/> + <TextView + android:id="@+id/wifi_summary" + android:textDirection="locale" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="start|center_vertical" + android:ellipsize="end" + android:textColor="?android:attr/textColorSecondary" + android:textSize="14sp" + android:fontFamily="google-sans" + android:layout_marginEnd="18dp"/> + </LinearLayout> + + <FrameLayout + android:layout_width="24dp" + android:layout_height="match_parent" + android:clickable="false" + android:layout_gravity="end|center_vertical"> + <ImageView + android:id="@+id/wifi_end_icon" + android:layout_gravity="end|center_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + </FrameLayout> + + </LinearLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index eb7638233efd..850b01717308 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -30,7 +30,6 @@ android:id="@+id/status_icon_area" android:layout_width="wrap_content" android:layout_height="match_parent" - android:paddingEnd="@dimen/system_icons_keyguard_padding_end" android:paddingTop="@dimen/status_bar_padding_top" android:layout_alignParentEnd="true" android:gravity="center_vertical|end" > @@ -39,6 +38,7 @@ android:layout_height="match_parent" android:layout_weight="1" android:layout_marginStart="@dimen/system_icons_super_container_margin_start" + android:layout_marginEnd="@dimen/status_bar_padding_end" android:gravity="center_vertical|end"> <include layout="@layout/system_icons" /> </FrameLayout> diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml index 075473aef9ac..566cd25e86a5 100644 --- a/packages/SystemUI/res/layout/media_view.xml +++ b/packages/SystemUI/res/layout/media_view.xml @@ -163,18 +163,6 @@ </LinearLayout> </LinearLayout> - <ImageView - android:id="@+id/media_seamless_fallback" - android:layout_width="@dimen/qs_seamless_fallback_icon_size" - android:layout_height="@dimen/qs_seamless_fallback_icon_size" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginStart="@dimen/qs_center_guideline_padding" - android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" - android:tint="?android:attr/textColor" - android:src="@drawable/ic_cast_connected" - android:forceHasOverlappingRendering="false" /> - <!-- Seek Bar --> <!-- As per Material Design on Biderectionality, this is forced to LTR in code --> <SeekBar diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index 5b9ca1b26158..966f9929b37c 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -26,17 +26,38 @@ android:focusable="true" android:theme="@style/Theme.SystemUI.QuickSettings.Header"> - <com.android.systemui.statusbar.policy.Clock - android:id="@+id/clock" + <LinearLayout + android:id="@+id/clock_container" android:layout_width="wrap_content" android:layout_height="match_parent" - android:minWidth="48dp" - android:minHeight="48dp" + android:orientation="horizontal" + android:layout_gravity="center_vertical|start" android:gravity="center_vertical|start" - android:paddingStart="@dimen/status_bar_left_clock_starting_padding" - android:paddingEnd="@dimen/status_bar_left_clock_end_padding" - android:singleLine="true" - android:textAppearance="@style/TextAppearance.QS.Status" /> + > + + <com.android.systemui.statusbar.policy.Clock + android:id="@+id/clock" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="48dp" + android:minHeight="48dp" + android:gravity="center_vertical|start" + android:paddingStart="@dimen/status_bar_left_clock_starting_padding" + android:paddingEnd="@dimen/status_bar_left_clock_end_padding" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.QS.Status" /> + + <com.android.systemui.statusbar.policy.VariableDateView + android:id="@+id/date_clock" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical|start" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.QS.Status" + systemui:longDatePattern="@string/abbrev_wday_month_day_no_year_alarm" + systemui:shortDatePattern="@string/abbrev_month_day_no_year" + /> + </LinearLayout> <include layout="@layout/qs_carrier_group" android:id="@+id/carrier_group" diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml index bff93a99258a..b1e8c386fe21 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml @@ -36,7 +36,7 @@ android:layout_weight="1" android:gravity="center_vertical|start" > - <com.android.systemui.statusbar.policy.DateView + <com.android.systemui.statusbar.policy.VariableDateView android:id="@+id/date" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -44,9 +44,16 @@ android:gravity="center_vertical" android:singleLine="true" android:textAppearance="@style/TextAppearance.QS.Status" - systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" /> + systemui:longDatePattern="@string/abbrev_wday_month_day_no_year_alarm" + systemui:shortDatePattern="@string/abbrev_month_day_no_year" + /> </FrameLayout> + <!-- We want this to be centered (to align with notches). In order to do that, the following + has to hold (in portrait): + * date_container and privacy_container must have the same width and weight + * header_text_container must be gone + --> <android.widget.Space android:id="@+id/space" android:layout_width="0dp" @@ -73,7 +80,7 @@ android:layout_weight="1" android:gravity="center_vertical|end" > - <include layout="@layout/ongoing_privacy_chip" /> + <include layout="@layout/ongoing_privacy_chip" /> </FrameLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml index d1cc01f0694e..c122829c01b6 100644 --- a/packages/SystemUI/res/layout/screen_record_dialog.xml +++ b/packages/SystemUI/res/layout/screen_record_dialog.xml @@ -113,6 +113,8 @@ android:layout_height="wrap_content" android:minHeight="48dp" android:layout_weight="1" + android:layout_gravity="fill_vertical" + android:gravity="center_vertical" android:text="@string/screenrecord_taps_label" android:textAppearance="?android:attr/textAppearanceMedium" android:fontFamily="@*android:string/config_headlineFontFamily" diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index bea50e87a29a..71e8fc9991ed 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -62,8 +62,7 @@ <com.android.systemui.statusbar.LightRevealScrim android:id="@+id/light_reveal_scrim" android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> + android:layout_height="match_parent" /> <include layout="@layout/status_bar_expanded" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 8229661fbc24..bfb6969f3724 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoem om skerm te vul"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Strek om skerm te vul"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock is gedeaktiveer"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Stoor tans skermkiekie..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou mikrofoon te gebruik."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou kamera te gebruik."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou kamera of mikrofoon te gebruik."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Toestel"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Ander toestel"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Wissel oorsig"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Gelaai"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Laai tans"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om oop te maak"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Stawing word vereis. Raak die vingerafdruksensor om te staaf."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Oproep aan die gang"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Gekoppel"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data sal nie outomaties koppel nie"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding nie"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen ander netwerke beskikbaar nie"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Geen netwerke beskikbaar nie"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Netwerkbesonderhede"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tik op \'n netwerk om te koppel"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontsluit om netwerke te bekyk"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Soek tans na netwerke …"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kon nie aan netwerk koppel nie"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 7f101d73b925..df4eafc7301f 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ማያ እንዲሞላ አጉላ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ማያ ለመሙለት ሳብ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ተሰናክሏል"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ይህ የእርስዎን ማይክሮፎን እንዲጠቀሙ የተፈቀደላቸው የሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻ እገዳን ያነሳል።"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ይህ ካሜራዎን እንዲጠቀሙ ለተፈቀደላቸው ሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻን እገዳ ያነሳል።"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ይህ የእርስዎን ካሜራ ወይም ማይክሮፎን እንዲጠቀሙ የተፈቀደላቸው የሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻ እገዳን ያነሳል።"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"መሣሪያ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ሌላ መሣሪያ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"አጠቃላይ እይታን ቀያይር"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ባትሪ ሞልቷል"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ኃይል በመሙላት ላይ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ለመክፈት የጣት አሻራ ይጠቀሙ"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ማረጋገጥ ያስፈልጋል። ለማረጋገጥ የጣት አሻራ ዳሳሹን ይንኩ።"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"በመካሄድ ላይ የስልክ ጥሪ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"የተንቀሳቃሽ ስልክ ውሂብ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"ተገናኝቷል"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"የተንቀሳቃሽ ስልክ ውሂብ በራስ-ሰር አይገናኝም"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ግንኙነት የለም"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ሌላ አውታረ መረብ የሉም"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ምንም አውታረ መረቦች የሉም"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"የአውታረ መረብ ዝርዝሮች"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ለመገናኘት አንድ አውታረ መረብ መታ ያድርጉ"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"አውታረ መረቦችን ለመመልከት ይክፈቱ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"አውታረ መረቦችን በመፈለግ ላይ…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ከአውታረ መረቡ ጋር መገናኘት አልተሳካም"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 8f230246a70e..28c2d7c328f7 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"تكبير/تصغير لملء الشاشة"</string> <string name="compat_mode_off" msgid="7682459748279487945">"توسيع بملء الشاشة"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"لقطة شاشة"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"تم إيقاف Smart Lock."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"جارٍ حفظ لقطة الشاشة..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string> @@ -442,7 +443,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الميكروفون."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الكاميرا."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الكاميرا أو الميكروفون."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"الجهاز"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"جهاز آخر"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تبديل \"النظرة العامة\""</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"تم الشحن"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"جارٍ الشحن"</string> @@ -1185,4 +1186,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"يمكنك استخدام بصمة الإصبع للفتح"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"المصادقة مطلوبة. المس مستشعر بصمات الإصبع للمصادقة."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"مكالمة هاتفية جارية"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"بيانات الجوّال"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"متصلة بالإنترنت"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"لن يتم تلقائيًا الاتصال ببيانات الجوّال."</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"لا يتوفّر اتصال بالإنترنت"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"لا تتوفّر شبكات أخرى."</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"لا تتوفّر أي شبكات."</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"تفاصيل الشبكة"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"انقر على إحدى الشبكات للاتصال بالإنترنت"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"فتح القفل لعرض الشبكات"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"جارٍ البحث عن شبكات…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"تعذّر الاتصال بالشبكة."</string> + <string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 093a609df093..a5d599c05850 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্ৰীন পূর্ণ কৰিবলৈ জুম কৰক"</string> <string name="compat_mode_off" msgid="7682459748279487945">"স্ক্ৰীন পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock অক্ষম কৰা হৈছে"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"এইটোৱে আপোনাৰ মাইক্ৰ\'ফ\'ন ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়া আটাইবোৰ এপ্ আৰু সেৱাৰ বাবে এক্সেছ অৱৰোধৰ পৰা আঁতৰায়।"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"এইটোৱে আপোনাৰ কেমেৰা ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়া আটাইবোৰ এপ্ আৰু সেৱাৰ বাবে এক্সেছ অৱৰোধৰ পৰা আঁতৰায়।"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"এইটোৱে আপোনাৰ কেমেৰা অথবা মাইক্ৰ\'ফ\'ন ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়া আটাইবোৰ এপ্ আৰু সেৱাৰ বাবে এক্সেছ অৱৰোধৰ পৰা আঁতৰায়।"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইচ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"অন্য ডিভাইচ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"অৱলোকন ট’গল কৰক"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"চ্চার্জ হ’ল"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"চ্চার্জ হৈ আছে"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলিবলৈ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণৰ আৱশ্যক। বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰিবলৈ ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক।"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"চলি থকা ফ’ন কল"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ম’বাইল ডেটা"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"সংযোজিত হৈ আছে"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ম’বাইল ডেটা স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"সংযোগ নাই"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"ৱাই-ফাই"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"নেটৱৰ্কৰ সবিশেষ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"সংযোগ কৰিবলৈ এটা নেটৱৰ্কত টিপক"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটৱর্ক চাবলৈ আনলক কৰক"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটৱৰ্ক সন্ধান কৰি থকা হৈছে…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটৱৰ্কৰ সৈতে সংযোগ কৰিব পৰা নগ\'ল"</string> + <string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 7e50b194000a..7a66f4ea0d6a 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock deaktivdir"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Kamera və mikrofon istifadə edən bütün tətbiq və xidmətlərə giriş verir."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera və mikrofon istifadə edən bütün tətbiq və xidmətlərə giriş verir."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera və mikrofon istifadə edən bütün tətbiq və xidmətlərə giriş verir."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Digər cihaz"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"İcmala Keçin"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Enerji yığılıb"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Enerji doldurulur"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmaq üçün barmaq izindən istifadə edin"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Doğrulanma tələb olunur. Doğrulamaq üçün barmaq izi sensoruna toxunun."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Davam edən zəng"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Qoşulub"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil data avtomatik qoşulmayacaq"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yoxdur"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Heç bir başqa şəbəkə əlçatan deyil"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Əlçatan şəbəkə yoxdur"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Şəbəkə məlumatları"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Qoşulmaq üçün şəbəkəyə toxunun"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Şəbəkələrə baxmaq üçün kilidi açın"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Şəbəkə axtarılır…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Şəbəkəyə qoşulmaq alınmadı"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index fe7ce0f51bd8..d7f37e495192 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj na celom ekranu"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci na ceo ekran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock je onemogućen"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Čuvanje snimka ekrana..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string> @@ -436,7 +437,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje mikrofona."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje kamere."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje kamere ili mikrofona."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Drugi uređaj"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Uključi/isključi pregled"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Napunjena je"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Puni se"</string> @@ -1167,4 +1168,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je potvrda identiteta. Dodirnite senzor za otisak prsta da biste potvrdili identitet."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktuelni telefonski poziv"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nije uspelo autom. povezivanje preko mob. podataka"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Veza nije uspostavljena"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalji o mreži"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da biste se povezali"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da biste videli mreže"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traže se mreže…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje sa mrežom nije uspelo"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 5da6cf8b9c35..a5d613cf7004 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Павял. на ўвесь экран"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Расцягн. на ўвесь экран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функцыя \"Smart Lock\" адключана"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Захаванне скрыншота..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць мікрафон."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць камеру."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць камеру ці мікрафон."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Прылада"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Іншая прылада"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Уключыць/выключыць агляд"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Зараджаны"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарадка"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Каб адкрыць, скарыстайце адбітак пальца"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Патрабуецца аўтэнтыфікацыя. Дакраніцеся да сканера адбіткаў пальцаў."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Бягучы тэлефонны выклік"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мабільная перадача даных"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Падключана"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мабільная перадача даных не ўключаецца аўтаматычна"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма падключэння"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Больш няма даступных сетак"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Няма даступных сетак"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Інфармацыя пра сетку"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Каб падключыцца, націсніце на сетку"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблакіраваць для прагляду сетак"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Выконваецца пошук сетак…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не ўдалося падключыцца да сеткі"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 742de25d539c..eee5adbb0c3b 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Мащаб – запълва екрана"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Разпъване – запълва екрана"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Екранна снимка"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функцията Smart Lock е деактивирана"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Екранната снимка се запазва..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват микрофона ви."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват камерата ви."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват камерата или микрофона ви."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Устройство"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Друго устройство"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Превключване на общия преглед"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Заредена"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарежда се"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Използвайте отпечатък за отваряне"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Изисква се удостоверяване на самоличността. За целта докоснете сензора за отпечатъци."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Текущо телефонно обаждане"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни данни"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Свързано"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Връзката за мобилни данни няма да е автоматична"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма връзка"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Няма други налични мрежи"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Няма налични мрежи"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Подробности за мрежата"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Докоснете мрежа, за да се свържете"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отключване с цел преглед на мрежите"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Търсят се мрежи…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Свързването с мрежата не бе успешно"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index b35ae1f1efde..59cb64c6d490 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট নিন"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock বন্ধ করা হয়েছে"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"এটার জন্য মাইক্রোফোনের অ্যাক্সেস সেই সব অ্যাপ এবং পরিষেবার জন্য আনব্লক হয়ে যাবে, যাতে আপনার মাইক্রোফোন ব্যবহার করার অনুমতি দেওয়া হয়েছে।"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"এটার জন্য ক্যামেরার অ্যাক্সেস সেই সব অ্যাপ এবং পরিষেবার জন্য আনব্লক হয়ে যাবে, যাতে আপনার ক্যামেরা ব্যবহারের অনুমতি দেওয়া হয়েছে।"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"এটার জন্য ক্যামেরা অথবা মাইক্রোফোনের অ্যাক্সেস সেই সব অ্যাপ এবং পরিষেবার জন্য আনব্লক হয়ে যাবে, যাতে আপনার ক্যামেরা অথবা মাইক্রোফোন ব্যবহারের অনুমতি দেওয়া হয়েছে।"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইস"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"অন্য ডিভাইস"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"\'এক নজরে\' বৈশিষ্ট্যটি চালু বা বন্ধ করুন"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"চার্জ হয়েছে"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"চার্জ হচ্ছে"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"যাচাইকরণ করতে হবে। যাচাইকরণ করতে আঙুলের ছাপের সেন্সরে টাচ করুন।"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ব্যবহারকারী এখন ফোনে কথা বলছেন"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"মোবাইল ডেটা নিজে থেকে কানেক্ট হবে না"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"কানেকশন নেই"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনও নেটওয়ার্ক উপলভ্য নেই"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"কোনও নেটওয়ার্ক উপলভ্য নেই"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"ওয়াই-ফাই"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"নেটওয়ার্কের বিবরণ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"কানেক্ট করতে একটি নেটওয়ার্কে ট্যাপ করুন"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটওয়ার্ক দেখার জন্য আনলক করুন"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string> + <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index b87739732e4b..af33862fee48 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Uvećaj prikaz na ekran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci prikaz na ekran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock je onemogućen"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spašavanje snimka ekrana..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string> @@ -436,7 +437,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vaš mikrofon."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vašu kameru."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vašu kameru ili mikrofon."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Drugi uređaj"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pregled uključivanja/isključivanja"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Napunjeno"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Punjenje"</string> @@ -1167,4 +1168,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor za otisak prsta da autentificirate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonski poziv u toku"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Prijenos podataka na mobilnoj mreži"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Prijenos podataka se neće automatski povezati"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani s mrežom"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Druge mreže nisu dostupne"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalji o mreži"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da se povežete"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da vidite mreže"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 460db84dc05a..f99ca66beb97 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per omplir pantalla"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estira per omplir pant."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock desactivat"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"S\'està desant captura de pantalla..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar el micròfon."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar la càmera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar la càmera o el micròfon."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositiu"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Un altre dispositiu"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activa o desactiva Aplicacions recents"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"S\'està carregant"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilitza l\'empremta digital per obrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticació necessària. Toca el sensor d\'empremtes digitals per autenticar-te."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Trucada en curs"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dades mòbils"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connectat"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Les dades mòbils no es connectaran automàticament"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sense connexió"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hi ha cap altra xarxa disponible"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No hi ha cap xarxa disponible"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalls de la xarxa"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca una xarxa per connectar-te"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueja per veure xarxes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"S\'estan cercant xarxes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No s\'ha pogut connectar a la xarxa"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f48c9fb1cd77..a128bf1d29d1 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Přiblížit na celou obrazovku"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Na celou obrazovku"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funkce Smart Lock je deaktivována"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ukládání snímku obrazovky..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš mikrofon."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš fotoaparát."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš fotoaparát či mikrofon."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Zařízení"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Další zařízení"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Přepnout přehled"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Nabito"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nabíjení"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"K otevření použijte otisk prstu"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Je vyžadováno ověření. Dotkněte se snímače otisků prstů."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Probíhající hovor"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilní data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Připojeno"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilní data se nebudou připojovat automaticky"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Žádné připojení"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Žádné další sítě nejsou k dispozici"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nejsou k dispozici žádné sítě"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Podrobnosti sítě"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Klepněte na síť, ke které se chcete připojit"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sítě uvidíte po odemknutí"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhledávání sítí…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Připojení k síti se nezdařilo"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 058e6784bc2e..a948a038b527 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom til fuld skærm"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stræk til fuld skærm"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock er deaktiveret"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gemmer screenshot..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge din mikrofon."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge dit kamera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge dit kamera eller din mikrofon."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Enhed"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Anden enhed"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Slå Oversigt til/fra"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Opladet"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Oplader"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Brug fingeraftryk for at åbne"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Godkendelse er påkrævet. Sæt fingeren på fingeraftrykslæseren for at godkende."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Igangværende telefonopkald"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Forbundet"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Der oprettes ikke automatisk mobildataforbindelse"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Der er ingen forbindelse"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Der er ingen andre tilgængelige netværk"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Der er ingen tilgængelige netværk"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Netværksoplysninger"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tryk på et netværk for at oprette forbindelse"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås op for at se netværk"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søger efter netværk…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Der kunne ikke oprettes forbindelse til netværket"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 50fcdfb7032a..4d00de573565 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom auf Bildschirmgröße"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Auf Bildschirmgröße anpassen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock deaktiviert"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"Bild gesendet"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot wird gespeichert..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot wird gespeichert..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dadurch wird die Blockierung des Zugriffs für alle Apps und Dienste aufgehoben, die dein Mikrofon verwenden dürfen."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dadurch wird die Blockierung des Zugriffs für alle Apps und Dienste aufgehoben, die deine Kamera verwenden dürfen."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dadurch wird die Blockierung des Zugriffs für alle Apps und Dienste aufgehoben, die deine Kamera oder dein Mikrofon verwenden dürfen."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Gerät"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Sonstiges Gerät"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Übersicht ein-/ausblenden"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Aufgeladen"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Wird aufgeladen"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentifizierung erforderlich. Tippe dazu einfach auf den Fingerabdrucksensor."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktiver Anruf"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Keine automatische Verbindung über mobile Daten"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Keine Verbindung"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Keine anderen Netzwerke verfügbar"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Keine Netzwerke verfügbar"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Netzwerkdetails"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tippe auf ein Netzwerk, um eine Verbindung herzustellen"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Entsperren, um Netzwerke anzuzeigen"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index b8d357f3ff95..0d5c959e37c9 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ζουμ σε πλήρη οθόνη"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Προβoλή σε πλήρη οθ."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Το Smart Lock έχει απενεργοποιηθεί"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Αποθήκ. στιγμιότυπου οθόνης..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν το μικρόφωνό σας."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν την κάμερά σας."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν την κάμερα ή το μικρόφωνό σας."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Συσκευή"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Άλλη συσκευή"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Εναλλαγή επισκόπησης"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Φορτίστηκε"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Φόρτιση"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Χρήση δακτυλικού αποτυπώματος για άνοιγμα"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Απαιτείται έλεγχος ταυτότητας. Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων για έλεγχο ταυτότητας."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Τηλεφωνική κλήση σε εξέλιξη"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Δεδομένα κινητής τηλεφωνίας"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Συνδέθηκε"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Χωρίς αυτόματη σύνδεση δεδομένων κινητ. τηλεφωνίας"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Χωρίς σύνδεση"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Δεν υπάρχουν άλλα διαθέσιμα δίκτυα"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Δεν υπάρχουν διαθέσιμα δίκτυα"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Λεπτομέρειες δικτύου"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Πατήστε ένα δίκτυο για να συνδεθείτε"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ξεκλειδώστε για προβολή δικτύων"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Αναζήτηση δικτύων…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Αποτυχία σύνδεσης στο δίκτυο"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index d69a95bba878..e47680e964cb 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 3666069ee54b..43f30bbb7210 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index d69a95bba878..e47680e964cb 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index d69a95bba878..e47680e964cb 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 030c5884d3e3..e0ff8b594304 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock disabled"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Charged"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charging"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index bb43d81596be..8533c120c8a4 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ocupar la pantalla"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estirar p/ ocupar la pantalla"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Se inhabilitó Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura de pantalla"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Esta acción desbloquea el acceso para todos los servicios y las apps que tengan permitido usar el micrófono."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Esta acción desbloquea el acceso para todos los servicios y las apps que tengan permitido usar la cámara."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Esta acción permite que todas las aplicaciones y servicios que tengan permiso puedan usar la cámara o el micrófono."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Otro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ocultar o mostrar Recientes"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargada"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella dactilar para abrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Se requiere de una autenticación. Toca el sensor de huellas dactilares para autenticarte."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Conexión establecida"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"No se conectarán automáticamente los datos móviles"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No hay redes disponibles"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles de la red"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Presiona una red para conectarte a ella"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver las redes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Se produjo un error al establecer conexión con la red"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index fd0f8651b221..533f368a6746 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ajustar"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Expandir para ajustar"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock inhabilitado"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Si lo haces, todas las aplicaciones y servicios que tengan permiso podrán usar tu micrófono."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Si lo haces, todas las aplicaciones y servicios que tengan permiso podrán usar tu cámara."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Si lo haces, todas las aplicaciones y servicios que tengan permiso podrán usar tu cámara o tu micrófono."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Otro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Mostrar u ocultar aplicaciones recientes"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargada"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella digital para abrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticación obligatoria. Toca el sensor de huellas digitales para autenticarte."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"No hay redes disponibles"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles de la red"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca una red para conectarte"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver redes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 6cd609fa6151..5bc39f13b2cc 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Suumi ekraani täitmiseks"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Venita ekraani täitmiseks"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock on keelatud"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Kuvatõmmise salvestamine ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud mikrofoni kasutada."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud kaamerat kasutada."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud kaamerat või mikrofoni kasutada."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Seade"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Muu seade"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Lehe Ülevaade sisse- ja väljalülitamine"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Laetud"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Laadimine"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Kasutage avamiseks sõrmejälge"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vajalik on autentimine. Puudutage autentimiseks sõrmejäljeandurit."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Käimasolev telefonikõne"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilne andmeside"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Ühendatud"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilset andmesideühendust ei looda automaatselt"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ühendus puudub"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ühtegi muud võrku pole saadaval"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Ühtegi võrku pole saadaval"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Võrgu üksikasjad"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Puudutage ühendamiseks võrku"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Võrkude vaatamiseks avage"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Võrkude otsimine …"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Võrguühenduse loomine ebaõnnestus"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index d0d020350620..aaa1387d7683 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Handiagotu pantaila betetzeko"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Luzatu pantaila betetzeko"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Desgaitu da Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Pantaila-argazkia gordetzen…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera edo mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dituzte."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Gailua"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Beste gailu bat"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aldatu ikuspegi orokorra"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Kargatuta"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Kargatzen"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Erabili hatz-marka irekitzeko"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentifikazioa behar da. Autentifikatzeko, ukitu hatz-marken sentsorea."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefono-dei bat abian da"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datu-konexioa"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> (<xliff:g id="NETWORKMODE">%2$s</xliff:g>)"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Konektatuta"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Ez da automatikoki aktibatuko datu-konexioa"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Konexiorik gabe"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ez dago beste sare erabilgarririk"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Ez dago sare erabilgarririk"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wifia"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Sarearen xehetasunak"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Sakatu sare bat hartara konektatzeko"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sareak ikusteko, desblokeatu pantaila"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Sareak bilatzen…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ezin izan da konektatu sarera"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index d1ddd8c042f4..a97fffb23b38 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"بزرگنمایی برای پر کردن صفحه"</string> <string name="compat_mode_off" msgid="7682459748279487945">"گسترده کردن برای پر کردن صفحه"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"نماگرفت"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock غیرفعال شد"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"تصویری ارسال کرد"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"در حال ذخیره نماگرفت..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"درحال ذخیره نماگرفت…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"با این کار دسترسی برای همه برنامهها و سرویسهایی که مجاز هستند از میکروفونتان استفاده کنند لغو انسداد میشود."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"با این کار دسترسی برای همه برنامهها و سرویسهایی که مجاز هستند از دوربینتان استفاده کنند لغو انسداد میشود."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"با این کار دسترسی برای همه برنامهها و دستگاههایی که مجاز هستند از دوربین یا میکروفونتان استفاده کنند لغو انسداد میشود."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"دستگاه"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"دستگاه دیگر"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تغییر وضعیت نمای کلی"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"شارژ کامل شد"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"در حال شارژ شدن"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"از اثر انگشت برای باز کردن قفل استفاده کنید"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"اصالتسنجی لازم است. برای اصالتسنجی، حسگر اثر انگشت را لمس کنید."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"تماس تلفنی درحال انجام"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"داده تلفن همراه"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"متصل است"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"داده تلفن همراه بهطور خودکار متصل نخواهد شد"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"اتصال برقرار نیست"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"شبکه دیگری وجود ندارد"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"شبکهای در دسترس نیست"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"جزئیات شبکه"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"برای اتصال به شبکه روی آن ضربه بزنید"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"برای مشاهده شبکهها، قفل صفحه را باز کنید"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"درحال جستجوی شبکه…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"اتصال به شبکه برقرار نشد"</string> + <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 4be1af938955..662a6d65697a 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoomaa koko näyttöön"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Venytä koko näyttöön"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock poistettu käytöstä"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Tallennetaan kuvakaappausta..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tämä kumoaa kaikkien sellaisten sovellusten ja palveluiden eston, joilla on lupa käyttää mikrofoniasi."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tämä kumoaa kaikkien sellaisten sovellusten ja palveluiden eston, joilla on lupa käyttää kameraasi."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tämä kumoaa eston kaikkien sellaisten sovellusten ja palveluiden osalta, joilla on lupa käyttää kameraasi tai mikrofoniasi."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Laite"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Muu laite"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Näytä/piilota viimeisimmät"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Ladattu"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Ladataan"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Avaa sormenjäljellä"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Todennus vaaditaan. Todenna koskettamalla sormenjälkitunnistinta."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Puhelu käynnissä"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilidata"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Yhdistetty"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilidata ei yhdisty automaattisesti"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ei yhteyttä"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ei muita verkkoja käytettävissä"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Ei verkkoja käytettävissä"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Verkon tiedot"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Muodosta yhteys napauttamalla verkkoa"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Avaa lukitus nähdäksesi verkot"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Etsitään verkkoja…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yhteyden muodostaminen verkkoon epäonnistui"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 12dcd3243909..249f12673bda 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Fonctionnalité Smart Lock désactivée"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Cette action débloque l\'accès pour toutes les applications et tous les services autorisés à utiliser le microphone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès pour toutes les applications et pour tous les services autorisés à utiliser l\'appareil photo."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès pour toutes les applications et tous les services autorisés à utiliser l\'appareil photo ou le microphone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Basculer l\'aperçu"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Chargée"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Charge en cours..."</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Servez-vous de votre empreinte digitale pour ouvrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Touchez le capteur d\'empreintes digitales pour vous authentifier."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Appel téléphonique en cours…"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données cellulaires"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connexion active"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Aucune connexion auto. des données cellulaires"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau n\'est accessible"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Aucun réseau n\'est accessible"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Détails du réseau"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Touchez un réseau pour vous y connecter"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouillez l\'écran pour afficher les réseaux Wi-Fi"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux en cours…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 6a08d8716677..77ed144db71e 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock désactivé"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Cette action débloque l\'accès à tous les services et applis autorisés à utiliser votre micro."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès à tous les services et applis autorisés à utiliser votre appareil photo."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès pour tous les services et applis autorisés à utiliser votre appareil photo ou votre micro."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activer/Désactiver l\'aperçu"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Chargé"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"En charge"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilisez votre empreinte pour ouvrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Appuyez sur le lecteur d\'empreintes digitales pour vous authentifier."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Appel téléphonique en cours"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Pas de connexion automatique des données mobiles"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau disponible"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Aucun réseau disponible"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Détails du réseau"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Appuyez sur un réseau pour vous connecter"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouiller pour afficher les réseaux"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index a32cf263d596..95f473119275 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock está desactivado"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Con esta acción desbloquearase o acceso ao micrófono para todas as aplicacións e servizos que teñan permiso para utilizalo."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Con esta acción desbloquearase o acceso á cámara para todas as aplicacións e servizos que teñan permiso para utilizala."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Con esta acción desbloquearase o acceso á cámara ou ao micrófono para todas as aplicacións e servizos que teñan permiso para utilizalos."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activar/desactivar Visión xeral"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Cargado"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Cargando"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa a impresión dixital para abrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Requírese autenticación. Para autenticarte, toca o sensor de impresión dixital."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada telefónica en curso"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móbiles"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectada"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Os datos móbiles non se conectarán automaticamente"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sen conexión"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Non hai outras redes dispoñibles"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Non hai redes dispoñibles"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles da rede"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca unha rede para conectarte a ela"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea a pantalla para ver as redes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Produciuse un erro ao conectarse á rede"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 5ed7ac3c0bac..829b056246b5 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"સ્ક્રીન ભરવા માટે ઝૂમ કરો"</string> <string name="compat_mode_off" msgid="7682459748279487945">"સ્ક્રીન ભરવા માટે ખેંચો"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock બંધ કરેલું છે"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"આ તમારા માઇક્રોફોનનો ઉપયોગ કરવાની મંજૂરી ધરાવતી તમામ ઍપ અને સેવાઓ માટે ઍક્સેસને અનબ્લૉક કરે છે."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"આ તમારા કૅમેરાનો ઉપયોગ કરવાની મંજૂરી ધરાવતી તમામ ઍપ અને સેવાઓ માટે ઍક્સેસને અનબ્લૉક કરે છે."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"આ તમારા કૅમેરા અથવા માઇક્રોફોનનો ઉપયોગ કરવાની મંજૂરી ધરાવતી તમામ ઍપ અને સેવાઓ માટે ઍક્સેસને અનબ્લૉક કરે છે."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ડિવાઇસ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"અન્ય ડિવાઇસ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ઝલકને ટૉગલ કરો"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ચાર્જ થઈ ગયું"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ચાર્જ થઈ રહ્યું છે"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"પ્રમાણીકરણ આવશ્યક છે. પ્રમાણિત કરવા માટે ફિંગરપ્રિન્ટ સેન્સરને ટચ કરો."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ફોન કૉલ ચાલુ છે"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"મોબાઇલ ડેટા ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"કોઈ કનેક્શન નથી"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"બીજાં કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"વાઇ-ફાઇ"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"નેટવર્કની વિગતો"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"કનેક્ટ કરવા માટે નેટવર્ક પર ટૅપ કરો"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"વાઇ-ફાઇ નેટવર્ક જોવા માટે અનલૉક કરો"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string> + <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index fb160269eeb3..dd4617da727b 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरने के लिए ज़ूम करें"</string> <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरने के लिए खींचें"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock की सुविधा बंद कर दी गई है"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सहेजा जा रहा है..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ऐसा करने से, माइक्रोफ़ोन का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें माइक्रोफ़ोन का इस्तेमाल करने की अनुमति दी गई है."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ऐसा करने से, कैमरे का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें कैमरे का इस्तेमाल करने की अनुमति दी गई है."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ऐसा करने से, कैमरा या माइक्रोफ़ोन का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें ये इस्तेमाल करने की अनुमति है."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"डिवाइस"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"अन्य डिवाइस"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"खास जानकारी टॉगल करें"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज हो गई है"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हो रही है"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि करना ज़रूरी है. पुष्टि करने के लिए, फ़िंगरप्रिंट सेंसर को छुएं."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"फ़ोन कॉल चल रहा है"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट हो गया"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा अपने-आप कनेक्ट नहीं होगा"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"इंटरनेट कनेक्शन नहीं है"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"कोई दूसरा नेटवर्क उपलब्ध नहीं है"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"कोई नेटवर्क उपलब्ध नहीं है"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"वाई-फ़ाई"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्क की जानकारी"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"इंटरनेट से कनेक्ट करने के लिए, किसी नेटवर्क पर टैप करें"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"वाई-फ़ाई नेटवर्क देखने के लिए, स्क्रीन को अनलॉक करें"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क खोजे जा रहे हैं…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्क से कनेक्ट नहीं किया जा सका"</string> + <string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 9ec657d8d19d..cf465a1422eb 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj i ispuni zaslon"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rastegni i ispuni zaslon"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snimka zaslona"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock onemogućen"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spremanje snimke zaslona..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string> @@ -436,7 +437,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg mikrofona."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg fotoaparata."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg fotoaparata ili mikrofona."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Ostali uređaji"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Uključivanje/isključivanje pregleda"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Napunjeno"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Punjenje"</string> @@ -1167,4 +1168,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor otiska prsta da biste se autentificirali."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonski poziv u tijeku"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna veza neće se automatski uspostaviti"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Pojedinosti o mreži"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da biste se povezali"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte za prikaz mreža"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 38a3213f9b8d..20a973bae866 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Nagyítás a kitöltéshez"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Nyújtás kitöltéshez"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock kikapcsolva"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Képernyőkép mentése..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a mikrofon használatát."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a kamera használatát."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a kamera vagy a mikrofon használatát."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Eszköz"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Más eszköz"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Áttekintés be- és kikapcsolása"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Feltöltve"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Töltés"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ujjlenyomat használata a megnyitáshoz"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Hitelesítés szükséges. Érintse meg az ujjlenyomat-érzékelőt a hitelesítéshez."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Folyamatban lévő telefonhívás"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiladat"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g>/<xliff:g id="STATE">%1$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Csatlakozva"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nincs automatikus mobiladat-kapcsolat"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nincs kapcsolat"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nincs több rendelkezésre álló hálózat"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nincs rendelkezésre álló hálózat"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Hálózati információk"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"A kapcsolódáshoz koppintson a kívánt hálózatra"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Hálózatok keresése…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nem sikerült hálózathoz csatlakozni."</string> + <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 1d8094a4f61c..17d7d75e8f23 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Խոշորացնել` էկրանը լցնելու համար"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ձգել` էկրանը լցնելու համար"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock-ն անջատված է"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Սքրինշոթը պահվում է…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր խոսափողն օգտագործելու թույլտվություն։"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր տեսախցիկն օգտագործելու թույլտվություն։"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր տեսախցիկը կամ խոսափողն օգտագործելու թույլտվություն։"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Սարք"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Այլ սարք"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Միացնել/անջատել համատեսքը"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Լիցքավորված է"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Լիցքավորվում է"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Բացելու համար օգտագործեք մատնահետքը"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Պահանջվում է նույնականացում։ Դրա համար մատը հպեք մատնահետքի սկաներին։"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ընթացիկ հեռախոսազանգ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Բջջային ինտերնետ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Միացած է"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Բջջային ինտերնետն ավտոմատ չի միանա"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Կապ չկա"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Այլ հասանելի ցանցեր չկան"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Հասանելի ցանցեր չկան"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Ցանցի տվյալներ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Հպեք ցանցին՝ միանալու համար"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ապակողպեք՝ ցանցերը դիտելու համար"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ցանցերի որոնում…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Չհաջողվեց միանալ ցանցին"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index fe3ce968b742..a4743c188479 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Perbesar utk mengisi layar"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rentangkn utk mngisi layar"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dinonaktifkan"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan screenshot..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ini akan berhenti memblokir akses untuk semua aplikasi dan layanan yang diizinkan menggunakan mikrofon."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ini akan berhenti memblokir akses untuk semua aplikasi dan layanan yang diizinkan menggunakan kamera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Langkah ini akan berhenti memblokir akses untuk semua aplikasi dan layanan yang diizinkan menggunakan kamera atau mikrofon."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Perangkat"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Perangkat lainnya"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktifkan Ringkasan"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Terisi penuh"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Mengisi daya"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan sidik jari untuk membuka"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Perlu autentikasi. Sentuh sensor sidik jari untuk melakukan autentikasi."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Panggilan telepon sedang berlangsung"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data seluler"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Terhubung"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data seluler tidak akan terhubung otomatis"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Tidak ada koneksi"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Jaringan lain tidak tersedia"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Jaringan tidak tersedia"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detail jaringan"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ketuk jaringan untuk menghubungkan"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat jaringan"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari jaringan …"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menghubungkan ke jaringan"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 01905542684d..d2dbf8db697d 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Fylla skjá með aðdrætti"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Teygja yfir allan skjáinn"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Slökkt á Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Vistar skjámynd…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Þetta veitir öllum forritum og þjónustum aðgang að hljóðnemanum þínum."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Þetta veitir öllum forritum og þjónustum aðgang að myndavélinni þinni."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Þetta veitir öllum forritum og þjónustum aðgang að myndavélinni og hljóðnemanum þínum."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Tæki"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Annað tæki"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kveikja/slökkva á yfirliti"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Fullhlaðin"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Í hleðslu"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Opna með fingrafari"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Auðkenningar krafist. Auðkenndu með því að snerta fingrafaralesarann."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Símtal í gangi"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Farsímagögn"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Tengt"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Farsímagögn tengjast ekki sjálfkrafa"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Engin tenging"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Engin önnur net í boði"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Ekkert net í boði"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Upplýsingar um net"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ýttu á net til að tengjast"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Taktu úr lás til að skoða netkerfi"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Leitar að netum…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ekki tókst að tengjast neti"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 0efab5ceb84e..81af8010c333 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per riempire schermo"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funzionalità Smart Lock disattivata"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare il microfono."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare la fotocamera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare la fotocamera o il microfono."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Altro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Attiva/disattiva la panoramica"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carica"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"In carica"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa l\'impronta per aprire"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticazione obbligatoria. Eseguila toccando il sensore di impronte digitali."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonata in corso"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dati mobili"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Connessione attiva"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nessuna connessione dati mobili automatica"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nessuna connessione"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nessun\'altra rete disponibile"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nessuna rete disponibile"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Dettagli rete"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tocca una rete per connetterti"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sblocca per visualizzare le reti"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ricerca di reti in corso…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Connessione alla rete non riuscita"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 1e4c9d66ed9c..0fa9c9a12716 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"הגדלת התצוגה למילוי המסך"</string> <string name="compat_mode_off" msgid="7682459748279487945">"מתיחה למילוי של המסך"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"השבתת את Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"צילום המסך נשמר..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"המערכת שומרת את צילום המסך..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במיקרופון."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במצלמה."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במצלמה או במיקרופון."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"מכשיר"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"מכשיר אחר"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"החלפת מצב של מסכים אחרונים"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"הסוללה טעונה"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"בטעינה"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"נדרש אימות. יש לגעת בחיישן טביעות האצבע כדי לבצע אימות."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"מתקיימת שיחה"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"חבילת גלישה"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"מחובר"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"החיבור לנתונים סלולריים לא מתבצע באופן אוטומטי"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"אין חיבור"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"אין רשתות זמינות אחרות"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"אין רשתות זמינות"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"פרטי הרשת"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"צריך להקיש על רשת כדי להתחבר"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string> + <string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 27259791f664..25f72343e4dd 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"画面サイズに合わせて拡大"</string> <string name="compat_mode_off" msgid="7682459748279487945">"画面サイズに合わせて拡大"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock は無効です"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"スクリーンショットを保存中..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"マイクの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"カメラの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"カメラやマイクの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"デバイス"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"その他のデバイス"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"概要を切り替え"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"充電が完了しました"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"充電しています"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"指紋を使って開いてください"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"認証が必要です。指紋認証センサーをタッチして認証してください。"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"モバイルデータ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"接続済み"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"モバイルデータには自動接続しません"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"接続なし"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"利用できるネットワークはありません"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ネットワークを利用できません"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ネットワークの詳細"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ネットワークをタップして接続"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ネットワークを表示するにはロック解除してください"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ネットワークを検索しています…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ネットワークに接続できませんでした"</string> + <string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 21e1c52ae136..2a736345e411 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string> <string name="compat_mode_off" msgid="7682459748279487945">"გაწიეთ ეკრანის შესავსებად."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock გათიშულია"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"სკრინშოტის შენახვა…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი მიკროფონის გამოყენების უფლება."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი კამერის გამოყენების უფლება."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი კამერის ან მიკროფონის გამოყენების უფლება."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"მოწყობილობა"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"სხვა მოწყობილობა"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"მიმოხილვის გადართვა"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"დატენილია"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"მიმდინარეობს დატენვა"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"გასახსნელად გამოიყენეთ თითის ანაბეჭდი"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"საჭიროა ავტორიზაცია. ავტორიზაციისთვის შეეხეთ თითის ანაბეჭდის სენსორს."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"მიმდინარე სატელეფონო ზარი"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"მობილური ინტერნეტი"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"დაკავშირებული"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"მობილურ ინტერნეტს ავტომატურად არ დაუკავშირდება"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"კავშირი არ არის"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"სხვა ქსელები მიუწვდომელია"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ქსელები მიუწვდომელია"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ქსელის დეტალები"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"დასაკავშირებლად შეეხეთ ქსელს"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"განბლოკვა ქსელების სანახავად"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"მიმდინარეობს ქსელების ძიება…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ქსელთან დაკავშირება ვერ ხერხდება"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 6a9a9b5d8d11..b09811af9616 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Экранды толтыру үшін ұлғайту"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтыру үшін созу"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock өшірілді"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншотты сақтауда…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Микрофоныңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Камераңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Камераңызды немесе микрофоныңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Құрылғы"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Басқа құрылғы"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Шолуды қосу/өшіру"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Зарядталды"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарядталуда"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ашу үшін саусақ ізін пайдаланыңыз."</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аутентификациядан өту қажет. Ол үшін саусақ ізін оқу сканерін түртіңіз."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Телефон қоңырауы бар"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильдік интернет"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Жалғанды"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобильдік интернет автоматты түрде қосылмайды."</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыс жоқ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Басқа қолжетімді желі жоқ"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Қолжетімді желілер жоқ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Желі деректері"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Желіге қосылу үшін оны түртіңіз."</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Желілерді көру үшін құлыпты ашыңыз."</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Маңайдағы желілер ізделуде…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Желіге қосылмады."</string> + <string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 080ba1958e24..ff8aadd45418 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ពង្រីកដើម្បីឲ្យពេញអេក្រង់"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ទាញដើម្បីឲ្យពេញអេក្រង់"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"បានបិទ Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បានផ្ញើរូបភាព"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"កំពុងរក្សាទុករូបថតអេក្រង់…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើមីក្រូហ្វូនរបស់អ្នក។"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើកាមេរ៉ារបស់អ្នក។"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើកាមេរ៉ា ឬមីក្រូហ្វូនរបស់អ្នក។"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ឧបករណ៍"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ឧបករណ៍ផ្សេងទៀត"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"បិទ/បើកទិដ្ឋភាពរួម"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"បានសាកថ្មពេញ"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"កំពុងសាកថ្ម"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ប្រើស្នាមម្រាមដៃ ដើម្បីបើក"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"តម្រូវឱ្យមានការផ្ទៀងផ្ទាត់។ សូមចុចឧបករណ៍ចាប់ស្នាមម្រាមដៃ ដើម្បីផ្ទៀងផ្ទាត់។"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ការហៅទូរសព្ទដែលកំពុងដំណើរការ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ទិន្នន័យទូរសព្ទចល័ត"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"បានភ្ជាប់"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ទិន្នន័យទូរសព្ទចល័តនឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"មិនមានការតភ្ជាប់ទេ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"មិនមានបណ្ដាញផ្សេងទៀតដែលអាចប្រើបានទេ"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"មិនមានបណ្ដាញដែលអាចប្រើបានទេ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ព័ត៌មានលម្អិតអំពីបណ្ដាញ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ចុចលើបណ្ដាញណាមួយ ដើម្បីភ្ជាប់"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ដោះសោដើម្បីមើលបណ្ដាញ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"កំពុងស្វែងរកបណ្ដាញ…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"មិនអាចភ្ជាប់បណ្ដាញបានទេ"</string> + <string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 8e97ebfb226a..07fc1114196a 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ಇದು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳಿಗೆ ಹಾಗೂ ಸೇವೆಗಳಿಗೆ ನಿಮ್ಮ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವುದಕ್ಕಾಗಿ ಇರುವ ಪ್ರವೇಶದ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆದುಹಾಕುತ್ತದೆ."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ಇದು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳಿಗೆ ಹಾಗೂ ಸೇವೆಗಳಿಗೆ ನಿಮ್ಮ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸುವುದಕ್ಕಾಗಿ ಇರುವ ಪ್ರವೇಶದ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆದುಹಾಕುತ್ತದೆ."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ಇದು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳಿಗೆ ಹಾಗೂ ಸೇವೆಗಳಿಗೆ ನಿಮ್ಮ ಕ್ಯಾಮರಾ ಅಥವಾ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವುದಕ್ಕಾಗಿ ಇರುವ ಪ್ರವೇಶದ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆದುಹಾಕುತ್ತದೆ."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ಸಾಧನ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ಅನ್ಯ ಸಾಧನ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ಟಾಗಲ್ ನ ಅವಲೋಕನ"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ದೃಢೀಕರಣದ ಅವಶ್ಯಕತೆಯಿದೆ. ದೃಢೀಕರಿಸಲು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಫೋನ್ ಕರೆ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ಮೊಬೈಲ್ ಡೇಟಾ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ಮೊಬೈಲ್ ಡೇಟಾ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ಯಾವುದೇ ಕನೆಕ್ಷನ್ ಇಲ್ಲ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ಇತರ ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"ವೈ‑ಫೈ"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ನೆಟ್ವರ್ಕ್ ವಿವರಗಳು"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ಕನೆಕ್ಟ್ ಮಾಡಲು ಒಂದು ನೆಟ್ವರ್ಕ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 371b7de67806..7e729d1da808 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"전체화면 모드로 확대"</string> <string name="compat_mode_off" msgid="7682459748279487945">"전체화면 모드로 확대"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 사용 중지됨"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"캡쳐화면 저장 중..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"카메라를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"카메라 또는 마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"기기"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"기타 기기"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"최근 사용 버튼 전환"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"충전됨"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"충전 중"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"지문으로 열기"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"인증이 필요합니다. 지문 센서를 터치하여 인증하세요."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"진행 중인 전화 통화"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"모바일 데이터"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"연결됨"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"모바일 데이터가 자동으로 연결되지 않음"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"연결되지 않음"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"사용 가능한 다른 네트워크가 없음"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"사용 가능한 네트워크가 없음"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"네트워크 세부정보"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"연결하려면 네트워크를 탭하세요"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"네트워크를 보려면 잠금 해제하세요"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"네트워크 검색 중…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"네트워크에 연결하지 못했습니다."</string> + <string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 404b9ac45179..d9f1d2c6495d 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Экрнд тлтр ү. чен өлч өзг"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтуруу ү-н чоюу"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock өчүрүлдү"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншот сакталууда…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Микрофонуңузду колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Камераны колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Камераңызды же микрофонуңузду колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Түзмөк"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Башка түзмөк"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Назар режимин өчүрүү/күйгүзүү"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Кубатталды"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Кубатталууда"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Манжаңыздын изи менен ачыңыз"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аныктыкты текшерүү талап кылынат. Аныктыгын текшерүү үчүн манжа изинин сенсоруна тийип коюңуз."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Учурдагы телефон чалуу"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилдик трафик"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Туташты"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилдик трафик автоматтык түрдө туташтырылбайт"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыш жок"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Башка тармактар жеткиликсиз"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Тармактар жеткиликтүү эмес"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Тармактын чоо-жайы"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Кайсы тармакка туташасыз?"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Тармактарды көрүү үчүн кулпусун ачыңыз"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Тармактар изделүүдө…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Тармакка туташпай калды"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 33fddef3efb3..c4fa48b69f86 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ປິດການນຳໃຊ້ Smart Lock ແລ້ວ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ນີ້ຈະຍົກເລີກການບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ໄມໂຄຣໂຟນຂອງທ່ານ."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ນີ້ຈະຍົກເລີກການບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບຂອງທ່ານ."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ນີ້ຈະປົດບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນຂອງທ່ານ."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ອຸປະກອນ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ອຸປະກອນອື່ນໆ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ສະຫຼັບພາບຮວມ"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ສາກເຕັມແລ້ວ."</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ກຳລັງສາກໄຟ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ໃຊ້ລາຍນິ້ວມືເພື່ອເປີດ"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ຕ້ອງພິສູດຢືນຢັນ. ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມືເພື່ອພິສູດຢືນຢັນ."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ສາຍໂທອອກ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ອິນເຕີເນັດມືຖື"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"ເຊື່ອມຕໍ່ແລ້ວ"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ຈະບໍ່ເຊື່ອມຕໍ່ອິນເຕີເນັດມືຖືອັດຕະໂນມັດ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ບໍ່ມີການເຊື່ອມຕໍ່"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ບໍ່ມີເຄືອຂ່າຍອື່ນທີ່ສາມາດໃຊ້ໄດ້"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ບໍ່ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ລາຍລະອຽດເຄືອຂ່າຍ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ແຕະເຄືອຂ່າຍໃດໜຶ່ງເພື່ອເຊື່ອມຕໍ່"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ປົດລັອກເພື່ອເບິ່ງເຄືອຂ່າຍ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ກຳລັງຊອກຫາເຄືອຂ່າຍ…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ເຊື່ອມຕໍ່ເຄືອຂ່າຍບໍ່ສຳເລັດ"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 94faaf42d1b9..3a35355935f7 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Keisti mast., kad atit. ekr."</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ištempti, kad atit. ekr."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrano kopija"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"„Smart Lock“ išjungta"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Išsaugoma ekrano kopija..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti mikrofoną."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti fotoaparatą."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti fotoaparatą ar mikrofoną."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Įrenginys"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Kitas įrenginys"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Perjungti apžvalgą"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Įkrautas"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Kraunamas"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Naudokite kontrolinį kodą, kad atidarytumėte"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Reikia nustatyti tapatybę. Nustatykite tapatybę palietę kontrolinio kodo jutiklį."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Vykstantis telefono skambutis"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiliojo ryšio duomenys"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Prisijungta"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Naud. mob. r. duomenis nebus autom. prisijungiama"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nėra ryšio"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nėra kitų pasiekiamų tinklų"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nėra pasiekiamų tinklų"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Išsami tinklo informacija"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Palieskite tinklą, kad prisijungtumėte"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Atrakinkite, kad peržiūrėtumėte visus tinklus"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ieškoma tinklų…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Jungiantis prie tinklo įvyko klaida"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 0d14405ea4fb..e5eaac58c6e4 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Tālumm., lai aizp. ekr."</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stiepiet, lai aizp. ekr."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrānuzņēmums"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Sistēma Smart Lock ir atspējota"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saglabā ekrānuzņēmumu…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string> @@ -436,7 +437,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Visas lietotnes un pakalpojumi, kurām ir atļauts izmantot mikrofonu, varēs tam piekļūt."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Visas lietotnes un pakalpojumi, kuriem ir atļauts izmantot kameru, varēs tai piekļūt."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Visas lietotnes un pakalpojumi, kuriem ir atļauts izmantot kameru vai mikrofonu, varēs tiem piekļūt."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Ierīce"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Cita ierīce"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pārskata pārslēgšana"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Akumulators uzlādēts"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Notiek uzlāde"</string> @@ -1167,4 +1168,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Atvēršanai izmantojiet pirksta nospiedumu"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Nepieciešama autentifikācija. Pieskarieties pirksta nospieduma sensoram, lai veiktu autentificēšanu."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Notiekošs tālruņa zvans"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilie dati"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Ir izveidots savienojums"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilo datu savienojums netiks veidots automātiski"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nav savienojuma"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nav pieejams neviens cits tīkls"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nav pieejams neviens tīkls"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Dati par tīklu"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Pieskarieties tīklam, lai izveidotu savienojumu"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lai skatītu tīklus, atbloķējiet"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Notiek tīklu meklēšana…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Neizdevās izveidot savienojumu ar tīklu"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 5fda8b211ab1..85771e3e0490 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај да се исполни екранот"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Растегни да се исполни екранот"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Слика од екранот"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Оневозможено е Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"испрати слика"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сликата на екранот се зачувува..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Сликата на екранот се зачувува..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на микрофонот."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на камерата."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на камерата или микрофонот."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Уред"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Друг уред"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Вклучи/исклучи преглед"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Наполнета"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Се полни"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Користете отпечаток за да се отвори"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна е проверка. Допрете го сензорот за отпечаток за да автентицирате."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Тековен телефонски повик"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилен интернет"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Поврзано"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилниот интернет не може автоматски да се поврзе"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Нема интернет-врска"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нема други достапни мрежи"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Нема достапни мрежи"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Детали за мрежата"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Допрете на мрежа за да се поврзете"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отклучете за да се прикажат мрежите"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Се пребаруваат мрежи…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не успеа да се поврзе на мрежата"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 17b634606643..db14ca8d1492 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"സ്ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string> <string name="compat_mode_off" msgid="7682459748279487945">"സ്ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock പ്രവർത്തനരഹിതമാക്കി"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"നിങ്ങളുടെ മൈക്രോഫോൺ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"നിങ്ങളുടെ ക്യാമറ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"നിങ്ങളുടെ ക്യാമറയോ മൈക്രോഫോണോ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ഉപകരണം"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"മറ്റ് ഉപകരണം"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"അവലോകനം മാറ്റുക"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ചാർജായി"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ചാർജ് ചെയ്യുന്നു"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"തുറക്കുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. പരിശോധിച്ചുറപ്പിക്കാൻ, വിരലടയാള സെൻസറിൽ സ്പർശിക്കുക."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"സജീവമായ ഫോൺ കോൾ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"മൊബൈൽ ഡാറ്റ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"കണക്റ്റ് ചെയ്തു"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"മൊബൈൽ ഡാറ്റ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"കണക്ഷനില്ല"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"മറ്റ് നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"വൈഫൈ"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"നെറ്റ്വർക്ക് വിശദാംശങ്ങൾ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"കണക്റ്റ് ചെയ്യാൻ ഒരു നെറ്റ്വർക്കിൽ ടാപ്പ് ചെയ്യുക"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"നെറ്റ്വർക്കുകൾ കാണാൻ അൺലോക്ക് ചെയ്യുക"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"നെറ്റ്വർക്കുകൾ തിരയുന്നു…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"നെറ്റ്വർക്കിൽ കണക്റ്റ് ചെയ്യാനായില്ല"</string> + <string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index a777bb397712..15414c3540fe 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Дэлгэц дүүргэх бол өсгөнө үү"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Дэлгэц дүүргэх бол татна уу"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Ухаалаг түгжээг идэвхгүй болгосон"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Дэлгэцийн агшинг хадгалж байна…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Энэ нь таны микрофоныг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Энэ нь таны камерыг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Энэ нь таны камер эсвэл микрофоныг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Төхөөрөмж"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Бусад төхөөрөмж"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Тоймыг асаах/унтраах"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Цэнэглэгдсэн"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Цэнэглэж байна"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Нээхийн тулд хурууны хээг ашиглана уу"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Баталгаажуулалт шаардлагатай. Баталгаажуулахын тулд хурууны хээ мэдрэгчид хүрнэ үү."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Үргэлжилж буй утасны дуудлага"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобайл дата"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Холбогдсон"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобайл дата автоматаар холбогдохгүй"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Холболт алга"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Өөр боломжтой сүлжээ байхгүй байна"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Боломжтой сүлжээ байхгүй байна"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Сүлжээний дэлгэрэнгүй мэдээлэл"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Холбогдохын тулд сүлжээг товшино уу"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Сүлжээг харахын тулд түгжээг тайлах"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Сүлжээ хайж байна…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Сүлжээнд холбогдож чадсангүй"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 6b5811a79667..1a4b3a1962ff 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string> <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock बंद केले"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"हे तुमचा मायक्रोफोन वापरण्याची परवानगी असलेल्या सर्व ॲप्स आणि सेवांसाठी अॅक्सेस अनब्लॉक करते."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"हे तुमचा कॅमेरा वापरण्याची परवानगी असलेल्या सर्व ॲप्स आणि सेवांसाठी अॅक्सेस अनब्लॉक करते."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"हे तुमचा कॅमेरा आणि मायक्रोफोन वापरण्याची परवानगी असलेल्या सर्व ॲप्स व सेवांसाठी अॅक्सेस अनब्लॉक करते."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"डिव्हाइस"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"इतर डिव्हाइस"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"अवलोकन टॉगल करा."</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज झाली"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज होत आहे"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"उघडण्यासाठी फिंगरप्रिंट वापरा"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ऑथेंटिकेशन आवश्यक आहे. ऑथेंटिकेट करण्यासाठी फिंगरप्रिंट सेन्सरला स्पर्श करा."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"फोन कॉल सुरू आहे"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट केले आहे"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा ऑटो-कनेक्ट होणार नाही"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"कोणतेही कनेक्शन नाही"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"इतर कोणतेही नेटवर्क उपलब्ध नाहीत"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"कोणतेही नेटवर्क उपलब्ध नाही"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"वाय-फाय"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्कचे तपशील"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"कनेक्ट करण्यासाठी नेटवर्कवर टॅप करा"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्क पाहण्यासाठी स्क्रीन अनलॉक करा"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क शोधत आहे…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कशी कनेक्ट करता आले नाही"</string> + <string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index b7d0246c4095..554b08748941 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zum untuk memenuhi skrin"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Regang utk memenuhi skrin"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dilumpuhkan"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan tangkapan skrin..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan mikrofon anda."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera anda."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera atau mikrofon anda."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Peranti"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Peranti lain"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Togol Ikhtisar"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Sudah dicas"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Mengecas"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan cap jari untuk membuka"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Pengesahan diperlukan. Sentuh penderia cap jari untuk pengesahan."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Panggilan telefon yang sedang berjalan"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data mudah alih"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Disambungkan"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data mudah alih tidak akan autosambung"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Tiada sambungan"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Tiada rangkaian lain yang tersedia"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Tiada rangkaian tersedia"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Butiran rangkaian"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ketik rangkaian untuk membuat sambungan"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat rangkaian"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari rangkaian…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menyambung kepada rangkaian"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 81d168b79065..c19dd2f405c9 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ဇူးမ်အပြည့်ဆွဲခြင်း"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ဖန်သားပြင်အပြည့်ဆန့်ခြင်း"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ပိတ်ထားသည်"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ဖန်သားပြင်ဓါတ်ပုံသိမ်းစဉ်.."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"၎င်းက သင့်မိုက်ခရိုဖုန်းသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"၎င်းက သင့်ကင်မရာသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"၎င်းက သင့်ကင်မရာ (သို့) မိုက်ခရိုဖုန်းသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"စက်"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"အခြားစက်ပစ္စည်း"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ဖွင့်၊ ပိတ် အနှစ်ချုပ်"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"အားသွင်းပြီး"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"အားသွင်းနေ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ဖွင့်ရန် လက်ဗွေကို သုံးပါ"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"အထောက်အထားစိစစ်ခြင်း လိုအပ်သည်။ အထောက်အထားစိစစ်ရန် လက်ဗွေ အာရုံခံကိရိယာကို ထိပါ။"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"လက်ရှိ ဖုန်းခေါ်ဆိုမှု"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"မိုဘိုင်းဒေတာက အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ချိတ်ဆက်မှုမရှိပါ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"အခြားကွန်ရက်များ မရှိပါ"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ကွန်ရက်များ မရှိပါ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ကွန်ရက် အသေးစိတ်များ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ချိတ်ဆက်ရန် ကွန်ရက်ကို တို့ပါ"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ကွန်ရက်များကြည့်ရန် ဖွင့်ပါ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ကွန်ရက်များကို ရှာဖွေနေသည်…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ကွန်ရက်သို့ ချိတ်ဆက်၍မရပါ"</string> + <string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 360c58b9e2dc..5deb61291c5a 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom for å fylle skjermen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Strekk for å fylle skjerm"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock er slått av"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Lagrer skjermdumpen …"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke mikrofonen."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke kameraet."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke kameraet eller mikrofonen."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Annen enhet"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Slå oversikten av eller på"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Oppladet"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Lader"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Bruk fingeravtrykk for å åpne"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering kreves. Trykk på fingeravtrykkssensoren for å autentisere."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående telefonsamtale"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Tilkoblet"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobildata kobler ikke til automatisk"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen tilkobling"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ingen andre nettverk er tilgjengelige"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Ingen nettverk er tilgjengelige"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Nettverksdetaljer"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trykk på et nettverk for å koble til"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index e5787b578430..d4362d5b6c73 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string> <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"स्मार्ट लक अफ गरिएको छ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"यसो गर्नुभयो भने माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"यसो गर्नुभयो भने क्यामेरा प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"यसो गर्नुभयो भने क्यामेरा वा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"यन्त्र"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"अर्को डिभाइड"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज भयो"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हुँदै छ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि गर्नु पर्ने हुन्छ। पुष्टि गर्न फिंगरप्रिन्ट सेन्सर छुनुहोस्।"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"जारी फोन कल"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा स्वतः कनेक्ट हुँदैन"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"इन्टरनेट छैन"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"अन्य नेटवर्क उपलब्ध छैनन्"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"कुनै पनि नेटवर्क उपलब्ध छैन"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्कसम्बन्धी विवरण"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"इन्टरनेट कनेक्ट गर्न कुनै नेटवर्कमा ट्याप गर्नुहोस्"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्कहरू हेर्न आफ्नो स्क्रिन अनलक गर्नुहोस्"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्कहरू खोजिँदै छन्…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कमा कनेक्ट गर्न सकिएन"</string> + <string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 7d75b6e20a1e..8c9a8782f1e0 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom om scherm te vullen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rek uit v. schermvulling"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock staat uit"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"heeft een afbeelding gestuurd"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot opslaan..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot opslaan..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je microfoon te gebruiken."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je camera te gebruiken."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je camera of microfoon te gebruiken."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Apparaat"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Ander apparaat"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Overzicht aan- of uitzetten"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Opgeladen"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Opladen"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om te openen"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Verificatie vereist. Raak de vingerafdruksensor aan om de verificatie uit te voeren."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Actief telefoongesprek"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Verbonden"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data maakt niet automatisch verbinding"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen andere netwerken beschikbaar"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Geen netwerken beschikbaar"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Netwerkgegevens"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tik op een netwerk om verbinding te maken"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontgrendel het scherm om netwerken te bekijken"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netwerken zoeken…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kan geen verbinding maken met het netwerk"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index c315bd855374..b43e902a27a5 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ସ୍କ୍ରୀନ୍କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ସ୍ମାର୍ଟ ଲକ୍ ଅକ୍ଷମ କରାଯାଇଛି"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ଆପଣଙ୍କ ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ଆପଣଙ୍କ କ୍ୟାମେରାକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ଆପଣଙ୍କ କ୍ୟାମେରା କିମ୍ବା ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ଡିଭାଇସ୍"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ଅନ୍ୟ ଡିଭାଇସ୍"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀକୁ ଟୋଗଲ୍ କରନ୍ତୁ"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ଚାର୍ଜ ହୋଇଗଲା"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ଚାର୍ଜ କରାଯାଉଛି"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ପ୍ରମାଣୀକରଣ ଆବଶ୍ୟକ। ପ୍ରମାଣୀକରଣ କରିବାକୁ ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ।"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ଚାଲୁଥିବା ଫୋନ୍ କଲ୍"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ମୋବାଇଲ ଡାଟା"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"ସଂଯୋଗ କରାଯାଇଛି"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ମୋବାଇଲ ଡାଟା ସ୍ୱତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ସଂଯୋଗ ନାହିଁ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ଅନ୍ୟ କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"ୱାଇ-ଫାଇ"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ନେଟୱାର୍କ ବିବରଣୀ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ସଂଯୋଗ କରିବାକୁ ଏକ ନେଟୱାର୍କରେ ଟାପ୍ କରନ୍ତୁ"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ନେଟୱାର୍କଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ନେଟୱାର୍କଗୁଡ଼ିକ ସନ୍ଧାନ କରାଯାଉଛି…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ନେଟୱାର୍କକୁ ସଂଯୋଗ କରିବାରେ ବିଫଳ ହୋଇଛି"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index d68ab4fe347a..d667813b9a93 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ਬੰਦ ਕੀਤਾ ਗਿਆ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ਇਹ ਉਹਨਾਂ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਲਈ ਪਹੁੰਚ ਨੂੰ ਅਣਬਲਾਕ ਕਰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਹਾਡਾ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਗਈ ਹੈ।"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ਇਹ ਉਹਨਾਂ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਲਈ ਪਹੁੰਚ ਨੂੰ ਅਣਬਲਾਕ ਕਰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਹਾਡਾ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਗਈ ਹੈ।"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ਇਹ ਉਹਨਾਂ ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਲਈ ਪਹੁੰਚ ਨੂੰ ਅਣਬਲਾਕ ਕਰਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਹਾਡਾ ਕੈਮਰਾ ਜਾਂ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਗਈ ਹੈ।"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"ਡੀਵਾਈਸ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ਹੋਰ ਡੀਵਾਈਸ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ਰੂਪ-ਰੇਖਾ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ਚਾਰਜ ਹੋਇਆ"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ਚਾਰਜ ਕਰ ਰਿਹਾ ਹੈ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ਖੋਲ੍ਹਣ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ਪ੍ਰਮਾਣੀਕਰਨ ਲੋੜੀਂਦਾ ਹੈ। ਪ੍ਰਮਾਣਿਤ ਕਰਨ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ।"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ਜਾਰੀ ਫ਼ੋਨ ਕਾਲ"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ਮੋਬਾਈਲ ਡਾਟਾ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"ਕਨੈਕਟ ਹੈ"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ਮੋਬਾਈਲ ਡਾਟਾ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ਕੋਈ ਹੋਰ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ਕੋਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"ਵਾਈ-ਫਾਈ"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ਨੈੱਟਵਰਕ ਵੇਰਵੇ"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ਕਨੈਕਟ ਕਰਨ ਲਈ ਕਿਸੇ ਨੈੱਟਵਰਕ \'ਤੇ ਟੈਪ ਕਰੋ"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ਨੈੱਟਵਰਕ ਖੋਜੇ ਜਾ ਰਹੇ ਹਨ…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 9aade18169ad..51fc45e49a3e 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Powiększ, aby wypełnić ekran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rozciągnij, aby wypełnić ekran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Wyłączono Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Zapisywanie zrzutu ekranu..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z mikrofonu."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z aparatu."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z aparatu lub mikrofonu."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Urządzenie"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Inne urządzenie"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Przełącz Przegląd"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Naładowana"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Ładowanie"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Wymagane uwierzytelnienie. Dotknij czytnika liniii papilarnych, by uwierzytelnić."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktywne połączenie"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilna transmisja danych"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Połączono"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna transmisja danych nie połączy się automatycznie"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Brak połączenia"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Brak innych dostępnych sieci"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Brak dostępnych sieci"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Szczegóły sieci"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Kliknij sieć, aby połączyć"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odblokuj, by wyświetlić sieci"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Szukam sieci…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nie udało się połączyć z siecią"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 0ebd73c6ae53..8109c31284a1 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"O Smart Lock foi desativado"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar seu microfone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera ou seu microfone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregado"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Carregando"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nenhuma rede disponível"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque em uma rede para se conectar"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index eec34684ff4a..222db52a59ff 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para preencher o ecrã"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Esticar p. caber em ec. int."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock desativado"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"A guardar captura de ecrã..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar o seu microfone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar a sua câmara."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar a sua câmara ou microfone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ativar/desativar Vista geral"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregada"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"A carregar"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilize a impressão digital para abrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação necessária. Toque no sensor de impressões digitais para autenticar."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada telefónica em curso"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Ligado"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Não é efetuada ligação de dados móveis automática"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem ligação"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Sem redes disponíveis"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque numa rede para estabelecer ligação"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"A procurar redes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Não foi possível estabelecer ligação à rede"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 0ebd73c6ae53..8109c31284a1 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"O Smart Lock foi desativado"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar seu microfone."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Essa ação desbloqueia o acesso para todos os apps e serviços com autorização para usar sua câmera ou seu microfone."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Carregado"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Carregando"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nenhuma rede disponível"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque em uma rede para se conectar"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 1e30ea713210..95d264707d0a 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom pt. a umple ecranul"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Înt. pt. a umple ecranul"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock dezactivat"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Se salv. captura de ecran..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string> @@ -436,7 +437,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi microfonul."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera sau microfonul."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Dispozitiv"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Alt dispozitiv"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Comutați secțiunea Recente"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Încărcată"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Se încarcă"</string> @@ -1167,4 +1168,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosiți amprenta ca să deschideți"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atingeți senzorul de amprentă pentru a vă autentifica."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Apel telefonic în desfășurare"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectat"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nu se conectează automat la date mobile"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nicio conexiune"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nu sunt disponibile alte rețele"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nicio rețea disponibilă"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detalii despre rețea"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Atingeți o rețea pentru a vă conecta"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblocați pentru a vedea rețelele"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 99465d54e124..58052ac079f7 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Подогнать по размерам экрана"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Растянуть на весь экран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Функция Smart Lock отключена."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сохранение..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование микрофона."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры или микрофона."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Устройство"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Другое устройство"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Переключить режим обзора"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Батарея заряжена"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Зарядка батареи"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Используйте отпечаток пальца для входа."</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Требуется аутентификация. Приложите палец к сканеру отпечатков."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Текущий вызов"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильный интернет"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Подключено"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Без автоподключения к мобильному интернету"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Нет подключения к интернету"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нет других доступных сетей"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Нет доступных сетей"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Сведения о сети"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Выберите сеть, чтобы подключиться"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Поиск сетей…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не удалось подключиться к сети"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 6ea2a0dd5d7a..b52ae9365750 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"තිරය පිරවීමට විශාලනය කරන්න"</string> <string name="compat_mode_off" msgid="7682459748279487945">"තිරය පිරවීමට අදින්න"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"තිර රුව"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock අබලයි"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"තිර රුව සුරකිමින්…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"මෙය ඔබගේ මයික්රෆෝනය භාවිත කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"මෙය ඔබගේ කැමරාව භාවිතා කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"මෙය ඔබගේ කැමරාව හෝ මයික්රෆෝනය භාවිත කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"උපාංගය"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"වෙනත් උපාංගය"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"දළ විශ්ලේෂණය ටොගල කරන්න"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"අරෝපිතයි"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ආරෝපණය වෙමින්"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"විවෘත කිරීමට ඇඟිලි සලකුණ භාවිත කරන්න"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"සත්යාපනය අවශ්යයි. සත්යාපනය කිරීමට ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ක්රියාත්මක වන දුරකථන ඇමතුම"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"ජංගම දත්ත"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"සම්බන්ධයි"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"ජංගම දත්ත ස්වංක්රියව සම්බන්ධ නොවනු ඇත"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"සම්බන්ධතාවයක් නැත"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ලබා ගත හැකි වෙනත් ජාල නැත"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ජාලය නොතිබේ"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"ජාල විස්තර"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"සම්බන්ධ වීමට ජාලයක් තට්ටු කරන්න"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ජාල බැලීමට අගුලු හරින්න"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ජාල සඳහා සොයමින්…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ජාලය වෙත සම්බන්ධ වීම අසාර්ථක විය"</string> + <string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 399b9797d21f..0590d3185aaf 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Priblížiť na celú obrazovku"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Na celú obrazovku"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Funkcia Smart Lock je deaktivovaná"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Prebieha ukladanie snímky obrazovky..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať mikrofón."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať fotoaparát."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať fotoaparát alebo mikrofón."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Zariadenie"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Iné zariadenie"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Prepnúť prehľad"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Nabitá"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nabíja sa"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorte odtlačkom prsta"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vyžaduje sa overenie. Dotknite sa senzora odtlačkov prstov."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Prebiehajúci telefonický hovor"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilné dáta"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Pripojené"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Automatické pripojenie cez mobilné dáta nefunguje"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bez pripojenia"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nie sú k dispozícii žiadne ďalšie siete"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nie sú k dispozícii žiadne siete"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Podrobnosti siete"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ak sa chcete pripojiť, klepnite na sieť"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odomknutím si zobrazte siete"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhľadávajú sa siete…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nepodarilo sa pripojiť k sieti"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 0c93bced9f41..0d1e1fb55590 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Povečava čez cel zaslon"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Raztegnitev čez zaslon"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Storitev Smart Lock je onemogočena."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Shranjev. posnetka zaslona ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo mikrofona."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo fotoaparata."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo fotoaparata ali mikrofona."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Naprava"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Druga naprava"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Vklop/izklop pregleda"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Baterija napolnjena"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Polnjenje"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Odprite s prstnim odtisom"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Zahtevano je preverjanje pristnosti. Za preverjanje pristnosti se dotaknite tipala prstnih odtisov."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Poteka klic"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Prenos podatkov v mobilnem omrežju"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna podatkovna povezava ne bo samodejna."</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ni povezave"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nobeno drugo omrežje ni na voljo"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Na voljo ni nobeno omrežje"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Podatki o omrežju"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Za vzpostavitev povezave se dotaknite omrežja."</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odklenite za ogled omrežij"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iskanje omrežij …"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Vzpostavljanje povezave z omrežjem ni uspelo."</string> + <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 7f101dbd3f57..8a40a3e33644 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock është çaktivizuar"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin mikrofonin tënd."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin kamerën tënde."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin kamerën ose mikrofonin tënd."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Pajisja"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Pajisje tjetër"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kalo te përmbledhja"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"I karikuar"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Po karikohet"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kërkohet vërtetimi. Prek sensorin e gjurmës së gishtit për t\'u vërtetuar."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonatë në vazhdim"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Të dhënat celulare nuk do të lidhen automatikisht"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nuk ka lidhje"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nuk ofrohet asnjë rrjet tjetër"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Nuk ofrohet asnjë rrjet"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Detajet e rrjetit"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trokit te një rrjet për t\'u lidhur"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Shkyçe për të parë rrjetet"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index cfd90e06669a..fb9d3d4533e9 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај на целом екрану"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Развуци на цео екран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Снимак екрана"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock је онемогућен"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Чување снимка екрана..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string> @@ -436,7 +437,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење микрофона."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење камере."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење камере или микрофона."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Уређај"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Други уређај"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Укључи/искључи преглед"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Напуњена је"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Пуни се"</string> @@ -1167,4 +1168,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Отворите помоћу отиска прста"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна је потврда идентитета. Додирните сензор за отисак прста да бисте потврдили идентитет."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Актуелни телефонски позив"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни подаци"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Повезано"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Није успело аутом. повезивање преко моб. података"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Веза није успостављена"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Није доступна ниједна друга мрежа"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Нема доступних мрежа"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Детаљи о мрежи"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Додирните мрежу да бисте се повезали"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Откључајте да бисте видели мреже"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Траже се мреже…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Повезивање са мрежом није успело"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 05aeffbc300d..d8e31d24bbc4 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zooma för att fylla skärm"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Dra för att fylla skärmen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skärmbild"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock har inaktiverats"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skärmbilden sparas ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmbilden sparas ..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda mikrofonen."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda kameran."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda kameran eller mikrofonen."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Annan enhet"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktivera och inaktivera översikten"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Laddat"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Laddar"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Öppna med fingeravtryck"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering krävs. Identifiera dig genom att trycka på fingeravtryckssensorn."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående samtal"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Ansluten"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Du ansluts inte till mobildata automatiskt"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen anslutning"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Inga andra nätverk är tillgängliga"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Det finns inga tillgängliga nätverk"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Nätverksinformation"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tryck på ett nätverk för att ansluta"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås upp för att visa nätverk"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 7f51e82683b7..27a25c07b39d 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Kuza ili kujaza skrini"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Tanua ili kujaza skrini"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Kipengele cha Smart Lock kimezimwa"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Hatua hii huruhusu programu na huduma zote zenye idhini zitumie maikrofoni yako."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Hatua hii huruhusu programu na huduma zote zenye idhini zitumie kamera yako."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Hatua hii huruhusu programu na huduma zote zenye idhini zitumie kamera au maikrofoni yako."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Kifaa"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Kifaa kingine"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Washa Muhtasari"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Betri imejaa"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Inachaji"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Tumia alama ya kidole kufungua"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Uthibitishaji unahitajika. Gusa kitambua alama ya kidole ili uthibitishe."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Simu inayoendelea"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data ya mtandao wa simu"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Imeunganishwa"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data ya mtandao wa simu haitaunganishwa kiotomatiki"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Hakuna muunganisho"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Hakuna mitandao mingine inayopatikana"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Hakuna mitandao inayopatikana"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Maelezo ya mtandao"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Gusa mtandao ili uunganishe"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Fungua ili uangalie mitandao"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Inatafuta mitandao…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Imeshindwa kuunganisha kwenye mtandao"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index da80b85b38bf..0a34dfd71c7e 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -95,4 +95,7 @@ <dimen name="controls_top_margin">24dp</dimen> <dimen name="global_actions_grid_item_layout_height">80dp</dimen> + + <!-- Internet panel related dimensions --> + <dimen name="internet_dialog_list_max_width">624dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 35407ebd9b69..01abf2af63a6 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"திரையை நிரப்ப அளவை மாற்று"</string> <string name="compat_mode_off" msgid="7682459748279487945">"திரையை நிரப்ப இழு"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock முடக்கப்பட்டது"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"உங்கள் மைக்ரோஃபோனைப் பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"உங்கள் கேமராவைப் பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"உங்கள் கேமராவையோ மைக்ரோஃபோனையோ பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"சாதனம்"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"பிற சாதனம்"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"மேலோட்டப் பார்வையை நிலைமாற்று"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"சார்ஜ் செய்யப்பட்டது"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"சார்ஜ் ஆகிறது"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"கைரேகையைப் பயன்படுத்தி திறந்திடுங்கள்"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"அங்கீகாரம் தேவை. கைரேகை சென்சாரைத் தொட்டு அங்கீகரியுங்கள்."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"செயலில் உள்ள மொபைல் அழைப்பு"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"மொபைல் டேட்டா"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"இணைக்கப்பட்டது"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"மொபைல் டேட்டாவுடன் தானாக இணைக்காது"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"இணைப்பு இல்லை"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"வேறு நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"வைஃபை"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"நெட்வொர்க் விவரங்கள்"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"இணையத்துடன் இணைய நெட்வொர்க்கைத் தட்டுங்கள்"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"நெட்வொர்க்குகளைத் தேடுகிறது…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string> + <string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index f20fff9a3dd4..21a0ca962a34 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్కు నింపేలా జూమ్ చేయండి"</string> <string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్కు నింపేలా విస్తరించండి"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్షాట్"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock డిజేబుల్ చేయబడింది"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్ను పంపారు"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"మీ మైక్రోఫోన్ను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్లు, సర్వీస్లకు యాక్సెస్ను ఇది అన్బ్లాక్ చేస్తుంది."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"మీ కెమెరాను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్లు, సర్వీస్లకు యాక్సెస్ను ఇది అన్బ్లాక్ చేస్తుంది."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"మీ కెమెరాను లేదా మైక్రోఫోన్ను ఉపయోగించడానికి అనుమతి పొందిన అన్ని యాప్లు, సర్వీస్లకు యాక్సెస్ను ఇది అన్బ్లాక్ చేస్తుంది."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"పరికరం"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"ఇతర పరికరం"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ఛార్జ్ చేయబడింది"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"ఛార్జ్ అవుతోంది"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ప్రామాణీకరణ అవసరం. ప్రామాణీకరించడానికి వేలిముద్ర సెన్సార్ను తాకండి."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ఫోన్ కాల్ జరుగుతోంది"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"మొబైల్ డేటా"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"కనెక్ట్ చేయబడింది"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"మొబైల్ డేటా ఆటోమెటిక్గా కనెక్ట్ అవ్వదు"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"కనెక్షన్ లేదు"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ఇతర నెట్వర్క్లేవీ అందుబాటులో లేవు"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"నెట్వర్క్లు అందుబాటులో లేవు"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"నెట్వర్క్ వివరాలు"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"కనెక్ట్ చేయడానికి నెట్వర్క్ను ట్యాప్ చేయండి"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"నెట్వర్క్లను చూడటానికి అన్లాక్ చేయండి"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్వర్క్ల కోసం సెర్చ్ చేస్తోంది…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్వర్క్కు కనెక్ట్ చేయడం విఫలమైంది"</string> + <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 1fd1313719dc..e053541ed94e 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ขยายจนเต็มหน้าจอ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ยืดจนเต็มหน้าจอ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ปิดใช้ Smart Lock แล้ว"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"กำลังบันทึกภาพหน้าจอ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้ไมโครโฟนของคุณ"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้กล้องของคุณ"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้กล้องหรือไมโครโฟนของคุณ"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"อุปกรณ์"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"อุปกรณ์อื่น"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"สลับภาพรวม"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ชาร์จแล้ว"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"กำลังชาร์จ"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ใช้ลายนิ้วมือเพื่อเปิด"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ต้องมีการตรวจสอบสิทธิ์ แตะเซ็นเซอร์ลายนิ้วมือเพื่อตรวจสอบสิทธิ์"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"กำลังโทรอยู่"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"อินเทอร์เน็ตมือถือ"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"เชื่อมต่อแล้ว"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"อินเทอร์เน็ตมือถือจะไม่เชื่อมต่ออัตโนมัติ"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"ไม่มีการเชื่อมต่อ"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ไม่มีเครือข่ายอื่นๆ ที่พร้อมใช้งาน"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"ไม่มีเครือข่ายที่พร้อมใช้งาน"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"รายละเอียดเครือข่าย"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"แตะเครือข่ายเพื่อเชื่อมต่อ"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"ปลดล็อกเพื่อดูเครือข่าย"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"กำลังค้นหาเครือข่าย…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"เชื่อมต่อเครือข่ายไม่สำเร็จ"</string> + <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 3837364887cf..9eb144916908 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"I-zoom upang punan screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"I-stretch upang mapuno screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Naka-disable ang Smart Lock"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nagpadala ng larawan"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Sine-save ang screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Sine-save ang screenshot…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong mikropono."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong camera."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong camera o mikropono."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Iba pang device"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"I-toggle ang Overview"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Tapos nang mag-charge"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Nagcha-charge"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gamitin ang fingerprint para buksan"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kailangan ng pag-authenticate. Pindutin ang sensor para sa fingerprint para mag-authenticate."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Kasalukuyang may tawag sa telepono"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Nakakonekta"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Hindi awtomatikong kokonekta ang mobile data"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Walang koneksyon"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Walang available na iba pang network"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Walang available na network"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Mga detalye ng network"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Mag-tap ng network para kumonekta"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"I-unlock para tingnan ang mga network"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Naghahanap ng mga network…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Hind nakakonekta sa network"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 1cd547ca7793..d1599bf95e67 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Yakınlaştır (ekranı kaplasın)"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Genişlet (ekran kapansın)"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock devre dışı"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ekran görüntüsü kaydediliyor..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Bu işlem, mikrofonunuzu kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Bu işlem, kameranızı kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Bu işlem, kamera veya mikrofonunuzu kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Diğer cihaz"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Genel bakışı aç/kapat"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Şarj oldu"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Şarj oluyor"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmak için parmak izi kullanın"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kimlik doğrulaması gerekiyor. Kimlik doğrulaması için parmak izi sensörüne dokunun."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Devam eden telefon görüşmesi"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil veri"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Bağlı"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil veri otomatik olarak bağlanmıyor"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yok"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Kullanılabilir başka ağ yok"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Kullanılabilir ağ yok"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Kablosuz"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Ağ bilgileri"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Bağlanmak için bir ağa dokunun"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ağları görmek için kilidi açın"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ağlar aranıyor…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ağa bağlanılamadı"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 70922aa77db3..482742a8419a 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Масштабув. на весь екран"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Розтягнути на весь екран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock вимкнено"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Збереження знімка екрана..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string> @@ -438,7 +439,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Усі додатки та сервіси, яким дозволено користуватися вашим мікрофоном, отримають доступ."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Усі додатки та сервіси, яким дозволено користуватися вашою камерою, отримають доступ."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Усі додатки та сервіси, яким дозволено користуватися вашою камерою чи мікрофоном, отримають доступ."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Пристрій"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Інший пристрій"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Увімкнути або вимкнути огляд"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Заряджено"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Заряджається"</string> @@ -1173,4 +1174,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Пройдіть автентифікацію. Для цього торкніться сканера відбитків пальців."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Активний телефонний виклик"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобільний Інтернет не підключатиметься автоматично"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Немає з\'єднання"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Інші мережі недоступні"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Немає доступних мереж"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Деталі мережі"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Натисніть мережу, до якої потрібно підключитися"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Розблокувати, щоб переглянути мережі"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Пошук мереж…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не вдалося підключитися до мережі"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 7ef014923960..9c80c7ea6bdc 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"پوری سکرین پر زوم کریں"</string> <string name="compat_mode_off" msgid="7682459748279487945">"پوری سکرین پر پھیلائیں"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock کو غیر فعال کیا گیا"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"اس سے آپ کا مائیکروفون استعمال کرنے کے لیے اجازت یافتہ سبھی ایپس اور سروسز کے لیے رسائی غیر مسدود ہو جاتی ہے۔"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"اس سے آپ کا کیمرا استعمال کرنے کے لیے اجازت یافتہ سبھی ایپس اور سروسز کے لیے رسائی غیر مسدود ہو جاتی ہے۔"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"اس سے آپ کا کیمرا یا مائیکروفون استعمال کرنے کے لیے اجازت یافتہ سبھی ایپس اور سروسز کے لیے رسائی غیر مسدود ہو جاتی ہے۔"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"آلہ"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"دوسرا آلہ"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"مجموعی جائزہ ٹوگل کریں"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"چارج ہوگئی"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"چارج ہو رہی ہے"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"توثیق مطلوب ہے۔ توثیق کرنے کے لیے فنگر پرنٹ سینسر کو ٹچ کریں۔"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"جاری فون کال"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g> / <xliff:g id="STATE">%1$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"موبائل ڈیٹا خودکار طور پر منسلک نہیں ہوگا"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"کوئی کنکشن نہیں"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"کوئی دوسرا نیٹ ورک دستیاب نہیں ہے"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"کوئی نیٹ ورکس دستیاب نہیں ہیں"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"نیٹ ورک کی تفصیلات"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"منسلک کرنے کے لیے نیٹ ورک پر تھپتھپائیں"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"نیٹ ورکس کو دیکھنے کے لیے غیر مقفل کریں"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string> + <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 08ac980d3bee..3b775770c0cd 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ekranga moslashtirish"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ekran hajmida cho‘zish"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinshot"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock faolsizlantirildi"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"rasm yuborildi"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinshot saqlanmoqda…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinshot saqlanmoqda…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Mikrofoningizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamerangizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera va mikrofoningizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Qurilma"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Boshqa qurilma"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Umumiy nazar rejimini almashtirish"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Quvvat oldi"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Quvvat olmoqda"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ochish uchun barmoq izidan foydalaning"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Haqiqiylikni tekshirish talab etiladi. Autentifikatsiya uchun barmoq izi skaneriga tegining."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Joriy telefon chaqiruvi"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil internet"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Ulandi"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil internetga avtomatik ulanmaydi"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Internetga ulanmagansiz"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Boshqa tarmoqlar mavjud emas"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Hech qanday tarmoq mavjud emas"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Tarmoq tafsilotlari"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ulanish uchun tarmoq ustiga bosing"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Tarmoqlarni koʻrish uchun qulfdan chiqaring"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Tarmoqlar qidirilmoqda…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Tarmoqqa ulanmadi"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 60b1232cd8a3..2d8d2de34c44 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"T.phóng để lấp đầy m.hình"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Giãn ra để lấp đầy m.hình"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Tính năng Smart Lock đã tắt"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Đang lưu ảnh chụp màn hình..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng micrô của bạn."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng máy ảnh của bạn."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng máy ảnh hoặc micrô của bạn."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Thiết bị"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Thiết bị khác"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Bật/tắt chế độ xem Tổng quan"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Đã sạc đầy"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Đang sạc"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Dùng vân tay để mở"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Bạn cần phải xác thực. Hãy chạm vào cảm biến vân tay để xác thực."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Đang gọi điện thoại"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dữ liệu di động"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Đã kết nối"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Dữ liệu di động sẽ không tự động kết nối"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Không có kết nối mạng"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Không có mạng nào khác"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Không có mạng"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Thông tin chi tiết về mạng"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Nhấn vào một mạng để kết nối"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Mở khóa để xem mạng"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Đang tìm mạng…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Không kết nối được với mạng"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 6c6c35ff6fb3..41ebca96539f 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"缩放以填满屏幕"</string> <string name="compat_mode_off" msgid="7682459748279487945">"拉伸以填满屏幕"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在保存屏幕截图..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"这将会为所有获准使用您麦克风的应用和服务启用这项权限。"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"这将会为所有获准使用您摄像头的应用和服务启用这项权限。"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"这将会为所有获准使用您的摄像头或麦克风的应用和服务启用这项权限。"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"设备"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"其他设备"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切换概览"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"已充满"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"正在充电"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指纹即可打开"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要进行身份验证。请轻触指纹传感器以验证身份。"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"正在进行通话"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"没有其他可用网络"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"没有可用网络"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"网络详情"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"点按要连接的网络"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"解锁即可查看网络"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜索网络…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"未能连接到网络"</string> + <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index f8ede3a55b88..63bc3f65e9a9 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string> <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"已傳送圖片"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕擷取畫面..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕擷取畫面..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"解除封鎖後,凡有存取權的應用程式和服務都可使用您的麥克風。"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"解除封鎖後,凡有存取權的應用程式和服務都可使用您的相機。"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"解除封鎖後,凡有存取權的應用程式和服務都可使用您的相機或麥克風。"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"裝置"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"其他裝置"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切換概覽"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"已完成充電"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"充電中"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。掂一下指紋感應器就可以驗證。"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"流動數據"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"不會自動連線至流動數據"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有連線"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網絡"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"沒有可用的網絡"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"網絡詳細資料"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"輕按網絡以連線"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖即可查看網絡"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網絡…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連接網絡"</string> + <string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index df84fb0699c9..eeb7522b67be 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string> <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock 已停用"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"傳送了一張圖片"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕截圖…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕截圖…"</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"這麼做可允許所有應用程式和服務使用麥克風。"</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"這麼做可允許所有應用程式和服務使用相機。"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"這麼做可允許所有應用程式和服務使用相機或麥克風。"</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"裝置"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"其他裝置"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切換總覽"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"已充飽"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"充電中"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。輕觸指紋感應器即可進行驗證。"</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"行動數據"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"系統將不會自動使用行動數據連線"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有網路連線"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網路"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"沒有可用的網路"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"網路詳細資料"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"輕觸要連線的網路"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖螢幕即可查看網路"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網路…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連上網路"</string> + <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index fe97daa7682e..29ae3695b472 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -77,6 +77,7 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Sondeza ukugcwalisa isikrini"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Nweba ukugcwalisa isikrini"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Isithombe-skrini"</string> + <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Ukhiye oSmathi ukhutshaziwe"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ilondoloz umfanekiso weskrini..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string> @@ -434,7 +435,7 @@ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa imakrofoni yakho."</string> <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa ikhamera yakho."</string> <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa ikhamera yakho noma imakrofoni."</string> - <string name="media_seamless_remote_device" msgid="177033467332920464">"Idivayisi"</string> + <string name="media_seamless_other_device" msgid="4654849800789196737">"Enye idivayisi"</string> <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Guqula ukubuka konke"</string> <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Kushajiwe"</string> <string name="expanded_header_battery_charging" msgid="1717522253171025549">"Iyashaja"</string> @@ -1161,4 +1162,18 @@ <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Sebenzisa izigxivizo zeminwe ukuvula"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Ukufakazela ubuqiniso budingekile. Thinta inzwa yezigxivizo zeminwe ukuze uqinisekise."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ikholi yefoni eqhubekayo"</string> + <string name="mobile_data_settings_title" msgid="3955246641380064901">"Idatha yeselula"</string> + <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> + <string name="mobile_data_connection_active" msgid="944490013299018227">"Ixhunyiwe"</string> + <string name="mobile_data_off_summary" msgid="3663995422004150567">"Idatha yeselula ngeke ikwazi ukuxhuma ngokuzenzekelayo"</string> + <string name="mobile_data_no_connection" msgid="1713872434869947377">"Alukho uxhumano"</string> + <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Awekho amanye amanethiwekhi atholakalayo"</string> + <string name="all_network_unavailable" msgid="4112774339909373349">"Awekho amanethiwekhi atholakalayo"</string> + <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string> + <string name="pref_title_network_details" msgid="1639455355897668883">"Imininingwane yenethiwekhi"</string> + <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Thepha inethiwekhi ukuze uxhume"</string> + <string name="unlock_to_view_networks" msgid="5072880496312015676">"Vula ukuze ubuke amanethiwekhi"</string> + <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iseshela amanethiwekhi…"</string> + <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yehlulekile ukuxhuma kunethiwekhi"</string> + <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string> </resources> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index b5337d363e12..3121ce37490a 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -69,6 +69,10 @@ <declare-styleable name="DateView"> <attr name="datePattern" format="string" /> </declare-styleable> + <declare-styleable name="VariableDateView"> + <attr name="longDatePattern" format="string" /> + <attr name="shortDatePattern" format="string" /> + </declare-styleable> <declare-styleable name="PseudoGridView"> <attr name="numColumns" format="integer" /> <attr name="verticalSpacing" format="dimension" /> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 2260d2175268..19633f2492cf 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -16,7 +16,7 @@ * limitations under the License. */ --> -<resources> +<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <drawable name="notification_number_text_color">#ffffffff</drawable> <drawable name="ticker_background_color">#ff1d1d1d</drawable> <drawable name="system_bar_background">@color/system_bar_background_opaque</drawable> @@ -187,7 +187,8 @@ <!-- UDFPS colors --> <color name="udfps_enroll_icon">#000000</color> <!-- 100% black --> <color name="udfps_moving_target_fill">#cc4285f4</color> <!-- 80% blue --> - <color name="udfps_enroll_progress">#ff669DF6</color> <!-- 100% blue --> + <color name="udfps_enroll_progress">#ff669DF6</color> <!-- blue 400 --> + <color name="udfps_enroll_progress_help">#ffEE675C</color> <!-- red 400 --> <!-- Logout button --> <color name="logout_button_bg_color">#ccffffff</color> @@ -281,4 +282,16 @@ <color name="wallet_card_border">#33FFFFFF</color> <color name="people_tile_background">@android:color/system_accent2_50</color> + + <!-- Internet Dialog --> + <!-- Material next state on color--> + <color name="settingslib_state_on_color">@color/settingslib_state_on</color> + <!-- Material next state off color--> + <color name="settingslib_state_off_color">@color/settingslib_state_off</color> + <!-- Material next track on color--> + <color name="settingslib_track_on_color">@color/settingslib_track_on</color> + <!-- Material next track off color--> + <color name="settingslib_track_off_color">@color/settingslib_track_off</color> + <color name="connected_network_primary_color">#191C18</color> + <color name="connected_network_secondary_color">#41493D</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index d274c917c26d..b6d5b3a6760a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -194,6 +194,11 @@ low powered state yet. --> <bool name="doze_long_press_uses_prox">true</bool> + <!-- Doze: whether the brightness sensor uses the proximity sensor. + If both this parameter and doze_selectively_register_prox are true, registration for the + brightness sensor won't occur when the display state is ON. --> + <bool name="doze_brightness_uses_prox">true</bool> + <!-- Doze: should notifications be used as a pulse signal? --> <bool name="doze_pulse_on_notifications">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 78db2a8a3485..15f209e557dd 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -331,11 +331,10 @@ <dimen name="global_screenshot_x_scale">80dp</dimen> <dimen name="screenshot_bg_protection_height">242dp</dimen> <dimen name="screenshot_preview_elevation">4dp</dimen> - <dimen name="screenshot_offset_y">24dp</dimen> + <dimen name="screenshot_offset_y">8dp</dimen> <dimen name="screenshot_offset_x">16dp</dimen> <dimen name="screenshot_dismiss_button_tappable_size">48dp</dimen> <dimen name="screenshot_dismiss_button_margin">8dp</dimen> - <dimen name="screenshot_action_container_offset_y">16dp</dimen> <dimen name="screenshot_action_container_corner_radius">18dp</dimen> <dimen name="screenshot_action_container_padding_vertical">4dp</dimen> <dimen name="screenshot_action_container_margin_horizontal">8dp</dimen> @@ -1299,8 +1298,6 @@ <dimen name="qs_media_action_margin">12dp</dimen> <dimen name="qs_seamless_height">24dp</dimen> <dimen name="qs_seamless_icon_size">12dp</dimen> - <dimen name="qs_seamless_fallback_icon_size">@dimen/qs_seamless_icon_size</dimen> - <dimen name="qs_seamless_fallback_margin">20dp</dimen> <dimen name="qs_footer_horizontal_margin">22dp</dimen> <dimen name="qs_media_disabled_seekbar_height">1dp</dimen> <dimen name="qs_media_enabled_seekbar_height">2dp</dimen> @@ -1590,4 +1587,42 @@ <!-- The padding between the icon and the text. --> <dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen> <dimen name="ongoing_call_chip_corner_radius">28dp</dimen> + + <!-- Internet panel related dimensions --> + <dimen name="internet_dialog_list_margin">12dp</dimen> + <dimen name="internet_dialog_list_max_height">646dp</dimen> + <dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen> + + <!-- Signal icon in internet dialog --> + <dimen name="signal_strength_icon_size">24dp</dimen> + + <!-- Internet dialog related dimensions --> + <dimen name="internet_dialog_corner_radius">24dp</dimen> + <!-- End margin of network layout --> + <dimen name="internet_dialog_network_layout_margin">16dp</dimen> + <!-- Size of switch bar in internet dialog --> + <dimen name="settingslib_switchbar_margin">16dp</dimen> + <!-- Minimum width of switch --> + <dimen name="settingslib_min_switch_width">52dp</dimen> + <!-- Size of layout margin left --> + <dimen name="settingslib_switchbar_padding_left">20dp</dimen> + <!-- Size of layout margin right --> + <dimen name="settingslib_switchbar_padding_right">20dp</dimen> + <!-- Radius of switch bar --> + <dimen name="settingslib_switch_bar_radius">35dp</dimen> + <!-- Margin of switch thumb --> + <dimen name="settingslib_switch_thumb_margin">4dp</dimen> + <!-- Size of switch thumb --> + <dimen name="settingslib_switch_thumb_size">20dp</dimen> + <!-- Width of switch track --> + <dimen name="settingslib_switch_track_width">52dp</dimen> + <!-- Height of switch track --> + <dimen name="settingslib_switch_track_height">28dp</dimen> + <!-- Radius of switch track --> + <dimen name="settingslib_switch_track_radius">35dp</dimen> + + <!-- Height percentage of the parent container occupied by the communal view --> + <item name="communal_source_height_percentage" format="float" type="dimen">0.80</item> + + <dimen name="drag_and_drop_icon_size">70dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a67021611812..ebf6e4888de4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -211,6 +211,8 @@ <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]--> <string name="global_action_screenshot">Screenshot</string> + <!-- Message shown in power menu when smart lock has been disabled [CHAR_LIMIT=NONE] --> + <string name="global_action_smart_lock_disabled">Smart Lock disabled</string> <!-- text to show in place of RemoteInput images when they cannot be shown. [CHAR LIMIT=50] --> @@ -1006,7 +1008,7 @@ <string name="sensor_privacy_start_use_mic_camera_dialog_content">This unblocks access for all apps and services allowed to use your camera or microphone.</string> <!-- Default name for the media device shown in the output switcher when the name is not available [CHAR LIMIT=30] --> - <string name="media_seamless_remote_device">Device</string> + <string name="media_seamless_other_device">Other device</string> <!-- QuickStep: Accessibility to toggle overview [CHAR LIMIT=40] --> <string name="quick_step_accessibility_toggle_overview">Toggle Overview</string> @@ -2992,4 +2994,37 @@ <string name="global_actions_change_description" translatable="false"><xliff:g>%1$s</xliff:g></string> <!-- URL for more information about changes in global actions --> <string name="global_actions_change_url" translatable="false"></string> + + <!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] --> + <string name="mobile_data_settings_title">Mobile data</string> + <!-- Provider Model: Summary text separator for preferences including a short description + (eg. "Connected / 5G"). [CHAR LIMIT=50] --> + <string name="preference_summary_default_combination"><xliff:g id="state" example="Connected">%1$s</xliff:g> / <xliff:g id="networkMode" example="LTE">%2$s</xliff:g></string> + <!-- Provider Model: + Summary indicating that a SIM has an active mobile data connection [CHAR LIMIT=50] --> + <string name="mobile_data_connection_active">Connected</string> + <!-- Provider Model: + Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] --> + <string name="mobile_data_off_summary">Mobile data won\u0027t auto\u2011connect</string> + <!-- Provider Model: + Summary indicating that a active SIM and no network available [CHAR LIMIT=50] --> + <string name="mobile_data_no_connection">No connection</string> + <!-- Provider Model: Summary indicating that no other networks available [CHAR LIMIT=50] --> + <string name="non_carrier_network_unavailable">No other networks available</string> + <!-- Provider Model: Summary indicating that no networks available [CHAR LIMIT=50] --> + <string name="all_network_unavailable">No networks available</string> + <!-- Provider Model: Panel title text for turning on the Wi-Fi networks. [CHAR LIMIT=40] --> + <string name="turn_on_wifi">Wi\u2011Fi</string> + <!-- Provider Model: Title for detail page of wifi network [CHAR LIMIT=30] --> + <string name="pref_title_network_details" msgid="7329759534269363308">"Network details"</string> + <!-- Provider Model: Panel subtitle for tapping a network to connect to internet. [CHAR LIMIT=60] --> + <string name="tap_a_network_to_connect">Tap a network to connect</string> + <!-- Provider Model: Panel subtitle for unlocking screen to view networks. [CHAR LIMIT=60] --> + <string name="unlock_to_view_networks">Unlock to view networks</string> + <!-- Provider Model: Wi-Fi settings. text displayed when Wi-Fi is on and network list is empty [CHAR LIMIT=50]--> + <string name="wifi_empty_list_wifi_on">Searching for networks\u2026</string> + <!-- Provider Model: Failure notification for connect --> + <string name="wifi_failed_connect_message">Failed to connect to network</string> + <!-- Provider Model: Title to see all the networks [CHAR LIMIT=50] --> + <string name="see_all_networks">See all</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 51eabf60385e..d25474255bfc 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -903,4 +903,52 @@ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen. --> <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item> </style> + + <style name="Animation.InternetDialog" parent="@android:style/Animation.InputMethod"> + </style> + + <style name="Widget.SliceView.Panel"> + <item name="titleSize">16sp</item> + <item name="rowStyle">@style/SliceRow</item> + <item name="android:background">?android:attr/colorBackgroundFloating</item> + </style> + + <style name="SliceRow"> + <!-- 2dp start padding for the start icon --> + <item name="titleItemStartPadding">2dp</item> + <item name="titleItemEndPadding">0dp</item> + + <!-- Padding between content and the start icon is 14dp --> + <item name="contentStartPadding">14dp</item> + <!-- Padding between content and end items is 16dp --> + <item name="contentEndPadding">16dp</item> + + <!-- Both side margins of end item are 16dp --> + <item name="endItemStartPadding">16dp</item> + <item name="endItemEndPadding">16dp</item> + + <!-- Both side margins of bottom divider are 12dp --> + <item name="bottomDividerStartPadding">12dp</item> + <item name="bottomDividerEndPadding">12dp</item> + + <item name="actionDividerHeight">32dp</item> + </style> + + <style name="Theme.SystemUI.Dialog.Internet"> + <item name="android:windowBackground">@drawable/internet_dialog_background</item> + </style> + + <style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault"> + <item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item> + </style> + + <style name="TrimmedHorizontalProgressBar" + parent="android:Widget.Material.ProgressBar.Horizontal"> + <item name="android:indeterminateDrawable"> + @drawable/progress_indeterminate_horizontal_material_trimmed + </item> + <item name="android:minHeight">4dp</item> + <item name="android:maxHeight">4dp</item> + </style> + </resources> diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml index d6c6a60d56b8..c3510b61e68a 100644 --- a/packages/SystemUI/res/xml/media_collapsed.xml +++ b/packages/SystemUI/res/xml/media_collapsed.xml @@ -44,23 +44,6 @@ /> <Constraint - android:id="@+id/media_seamless_fallback" - android:layout_width="@dimen/qs_seamless_fallback_icon_size" - android:layout_height="@dimen/qs_seamless_fallback_icon_size" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginStart="@dimen/qs_center_guideline_padding" - android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" - android:alpha="0.5" - android:visibility="gone" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline" - app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" - app:layout_constraintEnd_toEndOf="parent" - /> - - <Constraint android:id="@+id/album_art" android:layout_width="@dimen/qs_media_album_size_small" android:layout_height="@dimen/qs_media_album_size_small" diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml index 0e284e6ad631..6b83aae38e15 100644 --- a/packages/SystemUI/res/xml/media_expanded.xml +++ b/packages/SystemUI/res/xml/media_expanded.xml @@ -45,22 +45,6 @@ android:layout_marginBottom="4dp" /> <Constraint - android:id="@+id/media_seamless_fallback" - android:layout_width="@dimen/qs_seamless_fallback_icon_size" - android:layout_height="@dimen/qs_seamless_fallback_icon_size" - android:layout_marginTop="@dimen/qs_media_padding" - android:layout_marginBottom="16dp" - android:layout_marginStart="@dimen/qs_center_guideline_padding" - android:layout_marginEnd="@dimen/qs_seamless_fallback_margin" - android:alpha="0.5" - android:visibility="gone" - app:layout_constraintHorizontal_bias="1" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" - app:layout_constraintEnd_toEndOf="parent" - /> - - <Constraint android:id="@+id/album_art" android:layout_width="@dimen/qs_media_album_size" android:layout_height="@dimen/qs_media_album_size" diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java index 28a54d56b071..e115c342c4fe 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java @@ -132,8 +132,7 @@ public class KeyguardVisibilityHelper { .alpha(1f) .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable) .start(); - } else if (mUnlockedScreenOffAnimationController - .isScreenOffLightRevealAnimationPlaying()) { + } else if (mUnlockedScreenOffAnimationController.shouldAnimateInKeyguard()) { mKeyguardViewVisibilityAnimating = true; // Ask the screen off animation controller to animate the keyguard visibility for us diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index edb05691b530..dd3bb8990599 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -27,6 +27,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.android.settingslib.Utils; import com.android.systemui.Dumpable; @@ -79,7 +80,11 @@ public class LockIconView extends FrameLayout implements Dumpable { mLockIcon.setImageDrawable(drawable); } - void setCenterLocation(@NonNull PointF center, int radius) { + /** + * Set the location of the lock icon. + */ + @VisibleForTesting + public void setCenterLocation(@NonNull PointF center, int radius) { mLockIconCenter = center; mRadius = radius; diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 509ac8a6d9fe..2a4022ca57b6 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -46,6 +46,7 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; +import com.android.systemui.biometrics.AuthRippleController; import com.android.systemui.biometrics.UdfpsController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; @@ -67,7 +68,8 @@ import javax.inject.Inject; /** * Controls when to show the LockIcon affordance (lock/unlocked icon or circle) on lock screen. * - * This view will only be shown if the user has UDFPS or FaceAuth enrolled + * For devices with UDFPS, the lock icon will show at the sensor location. Else, the lock + * icon will show a set distance from the bottom of the device. */ @StatusBarComponent.StatusBarScope public class LockIconViewController extends ViewController<LockIconView> implements Dumpable { @@ -99,6 +101,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @NonNull private CharSequence mUnlockedLabel; @NonNull private CharSequence mLockedLabel; @Nullable private final Vibrator mVibrator; + @Nullable private final AuthRippleController mAuthRippleController; private boolean mIsDozing; private boolean mIsBouncerShowing; @@ -135,7 +138,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @NonNull AccessibilityManager accessibilityManager, @NonNull ConfigurationController configurationController, @NonNull @Main DelayableExecutor executor, - @Nullable Vibrator vibrator + @Nullable Vibrator vibrator, + @Nullable AuthRippleController authRippleController ) { super(view); mStatusBarStateController = statusBarStateController; @@ -148,6 +152,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mConfigurationController = configurationController; mExecutor = executor; mVibrator = vibrator; + mAuthRippleController = authRippleController; final Context context = view.getContext(); mUnlockIcon = mView.getContext().getResources().getDrawable( @@ -168,15 +173,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @Override protected void onInit() { + mAuthController.addCallback(mAuthControllerCallback); + mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; + mView.setAccessibilityDelegate(mAccessibilityDelegate); } @Override protected void onViewAttached() { - // we check this here instead of onInit since the FingerprintManager + FaceManager may not - // have started up yet onInit - mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; - updateConfiguration(); updateKeyguardShowing(); mUserUnlockedWithBiometric = false; @@ -497,8 +501,10 @@ public class LockIconViewController extends ViewController<LockIconView> impleme if (!wasClickableOnDownEvent()) { return; } + mDetectedLongPress = true; - if (mVibrator != null) { + if (onAffordanceClick() && mVibrator != null) { + // only vibrate if the click went through and wasn't intercepted by falsing mVibrator.vibrate( Process.myUid(), getContext().getOpPackageName(), @@ -506,8 +512,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme "lockIcon-onLongPress", VIBRATION_SONIFICATION_ATTRIBUTES); } - mDetectedLongPress = true; - onAffordanceClick(); } public boolean onSingleTapUp(MotionEvent e) { @@ -531,15 +535,24 @@ public class LockIconViewController extends ViewController<LockIconView> impleme return mDownDetected; } - private void onAffordanceClick() { + /** + * Whether we tried to launch the affordance. + * + * If falsing intercepts the click, returns false. + */ + private boolean onAffordanceClick() { if (mFalsingManager.isFalseTouch(LOCK_ICON)) { - return; + return false; } // pre-emptively set to true to hide view mIsBouncerShowing = true; + if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) { + mAuthRippleController.showRipple(FINGERPRINT); + } updateVisibility(); mKeyguardViewController.showBouncer(/* scrim */ true); + return true; } }); @@ -577,4 +590,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme public void setAlpha(float alpha) { mView.setAlpha(alpha); } + + private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { + @Override + public void onAllAuthenticatorsRegistered() { + mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; + updateConfiguration(); + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 76f30a80114a..00b33a416df4 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -65,6 +65,7 @@ import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.PowerUI; import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.qs.ReduceBrightColorsController; +import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.screenrecord.RecordingController; @@ -364,6 +365,7 @@ public class Dependency { @Inject Lazy<UiEventLogger> mUiEventLogger; @Inject Lazy<FeatureFlags> mFeatureFlagsLazy; @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy; + @Inject Lazy<InternetDialogFactory> mInternetDialogFactory; @Inject public Dependency() { @@ -578,6 +580,7 @@ public class Dependency { mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get); mProviders.put(EdgeBackGestureHandler.Factory.class, mEdgeBackGestureHandlerFactoryLazy::get); + mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get); mProviders.put(UiEventLogger.class, mUiEventLogger::get); mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get); mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get); diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index a68f79604b25..c8f8404ff0d6 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -20,6 +20,8 @@ import android.app.WallpaperColors; import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.RectF; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; @@ -29,7 +31,6 @@ import android.util.ArraySet; import android.util.Log; import android.util.MathUtils; import android.util.Size; -import android.view.DisplayInfo; import android.view.SurfaceHolder; import android.view.WindowManager; @@ -90,7 +91,7 @@ public class ImageWallpaper extends WallpaperService { mMiniBitmap = null; } - class GLEngine extends Engine { + class GLEngine extends Engine implements DisplayListener { // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin) // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail. @VisibleForTesting @@ -102,15 +103,15 @@ public class ImageWallpaper extends WallpaperService { private EglHelper mEglHelper; private final Runnable mFinishRenderingTask = this::finishRendering; private boolean mNeedRedraw; - private int mWidth = 1; - private int mHeight = 1; + + private boolean mDisplaySizeValid = false; + private int mDisplayWidth = 1; + private int mDisplayHeight = 1; + private int mImgWidth = 1; private int mImgHeight = 1; - private float mPageWidth = 1.f; - private float mPageOffset = 1.f; - GLEngine() { - } + GLEngine() { } @VisibleForTesting GLEngine(Handler handler) { @@ -124,13 +125,23 @@ public class ImageWallpaper extends WallpaperService { mRenderer = getRendererInstance(); setFixedSizeAllowed(true); updateSurfaceSize(); - Rect window = getDisplayContext() - .getSystemService(WindowManager.class) - .getCurrentWindowMetrics() - .getBounds(); - mHeight = window.height(); - mWidth = window.width(); + mRenderer.setOnBitmapChanged(this::updateMiniBitmap); + getDisplayContext().getSystemService(DisplayManager.class) + .registerDisplayListener(this, mWorker.getThreadHandler()); + } + + @Override + public void onDisplayAdded(int displayId) { } + + @Override + public void onDisplayRemoved(int displayId) { } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == getDisplayContext().getDisplayId()) { + mDisplaySizeValid = false; + } } EglHelper getEglHelperInstance() { @@ -154,26 +165,10 @@ public class ImageWallpaper extends WallpaperService { if (pages == mPages) return; mPages = pages; if (mMiniBitmap == null || mMiniBitmap.isRecycled()) return; - updateShift(); mWorker.getThreadHandler().post(() -> computeAndNotifyLocalColors(new ArrayList<>(mColorAreas), mMiniBitmap)); } - private void updateShift() { - if (mImgHeight == 0) { - mPageOffset = 0; - mPageWidth = 1; - return; - } - // calculate shift - DisplayInfo displayInfo = new DisplayInfo(); - getDisplayContext().getDisplay().getDisplayInfo(displayInfo); - int screenWidth = displayInfo.getNaturalWidth(); - float imgWidth = Math.min(mImgWidth > 0 ? screenWidth / (float) mImgWidth : 1.f, 1.f); - mPageWidth = imgWidth; - mPageOffset = (1 - imgWidth) / (float) (mPages - 1); - } - private void updateMiniBitmap(Bitmap b) { if (b == null) return; int size = Math.min(b.getWidth(), b.getHeight()); @@ -204,6 +199,8 @@ public class ImageWallpaper extends WallpaperService { @Override public void onDestroy() { + getDisplayContext().getSystemService(DisplayManager.class) + .unregisterDisplayListener(this); mMiniBitmap = null; mWorker.getThreadHandler().post(() -> { mRenderer.finish(); @@ -268,6 +265,16 @@ public class ImageWallpaper extends WallpaperService { * (1-Wr)]. */ private RectF pageToImgRect(RectF area) { + if (!mDisplaySizeValid) { + Rect window = getDisplayContext() + .getSystemService(WindowManager.class) + .getCurrentWindowMetrics() + .getBounds(); + mDisplayWidth = window.width(); + mDisplayHeight = window.height(); + mDisplaySizeValid = true; + } + // Width of a page for the caller of this API. float virtualPageWidth = 1f / (float) mPages; float leftPosOnPage = (area.left % virtualPageWidth) / virtualPageWidth; @@ -275,12 +282,24 @@ public class ImageWallpaper extends WallpaperService { int currentPage = (int) Math.floor(area.centerX() / virtualPageWidth); RectF imgArea = new RectF(); + + if (mImgWidth == 0 || mImgHeight == 0 || mDisplayWidth <= 0 || mDisplayHeight <= 0) { + return imgArea; + } + imgArea.bottom = area.bottom; imgArea.top = area.top; + + float imageScale = Math.min(((float) mImgHeight) / mDisplayHeight, 1); + float mappedScreenWidth = mDisplayWidth * imageScale; + float pageWidth = Math.min(1.0f, + mImgWidth > 0 ? mappedScreenWidth / (float) mImgWidth : 1.f); + float pageOffset = (1 - pageWidth) / (float) (mPages - 1); + imgArea.left = MathUtils.constrain( - leftPosOnPage * mPageWidth + currentPage * mPageOffset, 0, 1); + leftPosOnPage * pageWidth + currentPage * pageOffset, 0, 1); imgArea.right = MathUtils.constrain( - rightPosOnPage * mPageWidth + currentPage * mPageOffset, 0, 1); + rightPosOnPage * pageWidth + currentPage * pageOffset, 0, 1); if (imgArea.left > imgArea.right) { // take full page imgArea.left = 0; @@ -293,7 +312,6 @@ public class ImageWallpaper extends WallpaperService { private List<WallpaperColors> getLocalWallpaperColors(@NonNull List<RectF> areas, Bitmap b) { List<WallpaperColors> colors = new ArrayList<>(areas.size()); - updateShift(); for (int i = 0; i < areas.size(); i++) { RectF area = pageToImgRect(areas.get(i)); if (area == null || !LOCAL_COLOR_BOUNDS.contains(area)) { diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index affad7a57d86..8c63f7bec23c 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -438,6 +438,12 @@ public class SwipeHelper implements Gefingerpoken { private boolean mCancelled; @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + mCallback.onBeginDrag(animView); + } + + @Override public void onAnimationCancel(Animator animation) { mCancelled = true; } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java index 81a13a236685..408201558a9b 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java @@ -57,7 +57,9 @@ public class AssistOrbController { public void run() { mView.removeCallbacks(this); mView.show(false /* show */, true /* animate */, () -> { - mWindowManager.removeView(mView); + if (mView.isAttachedToWindow()) { + mWindowManager.removeView(mView); + } }); } }; diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt index c9e67715decb..5616a00592f2 100644 --- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt @@ -40,10 +40,10 @@ import com.android.systemui.people.widget.PeopleBackupHelper * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0, * indicating that restoring is finished for a given user. */ -class BackupHelper : BackupAgentHelper() { +open class BackupHelper : BackupAgentHelper() { companion object { - private const val TAG = "BackupHelper" + const val TAG = "BackupHelper" internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite" private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 3f61d3c6af9a..fd37b3509a4e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -126,6 +126,7 @@ public class AuthContainerView extends LinearLayout boolean mCredentialAllowed; boolean mSkipIntro; long mOperationId; + long mRequestId; @BiometricMultiSensorMode int mMultiSensorConfig; } @@ -172,6 +173,12 @@ public class AuthContainerView extends LinearLayout return this; } + /** Unique id for this request. */ + public Builder setRequestId(long requestId) { + mConfig.mRequestId = requestId; + return this; + } + /** The multi-sensor mode. */ public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) { mConfig.mMultiSensorConfig = multiSensorConfig; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 0ce1846e7745..0790af94f287 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -42,6 +42,7 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; @@ -49,6 +50,7 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.util.SparseBooleanArray; import android.view.MotionEvent; import android.view.WindowManager; @@ -76,6 +78,9 @@ import kotlin.Unit; /** * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the * appropriate biometric UI (e.g. BiometricDialogView). + * + * Also coordinates biometric-related things, such as UDFPS, with + * {@link com.android.keyguard.KeyguardUpdateMonitor} */ @SysUISingleton public class AuthController extends SystemUI implements CommandQueue.Callbacks, @@ -115,6 +120,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps; @Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps; + @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser; + private class BiometricTaskStackListener extends TaskStackListener { @Override public void onTaskStackChanged() { @@ -122,6 +129,21 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } + private final FingerprintStateListener mFingerprintStateListener = + new FingerprintStateListener() { + @Override + public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { + Log.d(TAG, "onEnrollmentsChanged, userId: " + userId + + ", sensorId: " + sensorId + + ", hasEnrollments: " + hasEnrollments); + for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) { + if (prop.sensorId == sensorId) { + mUdfpsEnrolledForUser.put(userId, hasEnrollments); + } + } + } + }; + @NonNull private final IFingerprintAuthenticatorsRegisteredCallback mFingerprintAuthenticatorsRegisteredCallback = @@ -436,6 +458,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mUdfpsControllerFactory = udfpsControllerFactory; mSidefpsControllerFactory = sidefpsControllerFactory; mWindowManager = windowManager; + mUdfpsEnrolledForUser = new SparseBooleanArray(); mOrientationListener = new BiometricOrientationEventListener(context, () -> { onOrientationChanged(); @@ -474,6 +497,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (mFingerprintManager != null) { mFingerprintManager.addAuthenticatorsRegisteredCallback( mFingerprintAuthenticatorsRegisteredCallback); + mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener); } mTaskStackListener = new BiometricTaskStackListener(); @@ -501,7 +525,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, + int userId, long operationId, String opPackageName, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { @Authenticators.Types final int authenticators = promptInfo.getAuthenticators(); @@ -515,6 +539,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, + ", credentialAllowed: " + credentialAllowed + ", requireConfirmation: " + requireConfirmation + ", operationId: " + operationId + + ", requestId: " + requestId + ", multiSensorConfig: " + multiSensorConfig); } SomeArgs args = SomeArgs.obtain(); @@ -526,6 +551,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, args.argi1 = userId; args.arg6 = opPackageName; args.arg7 = operationId; + args.arg8 = requestId; args.argi2 = multiSensorConfig; boolean skipAnimation = false; @@ -629,6 +655,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (mCurrentDialog == null) { // Could be possible if the caller canceled authentication after credential success // but before the client was notified. + if (DEBUG) Log.d(TAG, "dialog already gone"); return; } @@ -670,7 +697,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, return false; } - return mFingerprintManager.hasEnrolledTemplatesForAnySensor(userId, mUdfpsProps); + return mUdfpsEnrolledForUser.get(userId); } private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { @@ -683,6 +710,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, final int userId = args.argi1; final String opPackageName = (String) args.arg6; final long operationId = (long) args.arg7; + final long requestId = (long) args.arg8; final @BiometricMultiSensorMode int multiSensorConfig = args.argi2; // Create a new dialog but do not replace the current one yet. @@ -695,6 +723,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, opPackageName, skipAnimation, operationId, + requestId, multiSensorConfig); if (newDialog == null) { @@ -772,7 +801,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName, - boolean skipIntro, long operationId, + boolean skipIntro, long operationId, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { return new AuthContainerView.Builder(mContext) .setCallback(this) @@ -782,11 +811,16 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, .setOpPackageName(opPackageName) .setSkipIntro(skipIntro) .setOperationId(operationId) + .setRequestId(requestId) .setMultiSensorConfig(multiSensorConfig) .build(sensorIds, credentialAllowed, mFpProps, mFaceProps); } - interface Callback { + /** + * AuthController callback used to receive signal for when biometric authenticators are + * registered. + */ + public interface Callback { /** * Called when authenticators are registered. If authenticators are already * registered before this call, this callback will never be triggered. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 53fd9a3aa827..dac6f9cc16ac 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -43,7 +43,6 @@ import android.os.Looper; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.SystemClock; import android.os.Trace; import android.os.VibrationEffect; import android.os.Vibrator; @@ -76,6 +75,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.Execution; +import com.android.systemui.util.time.SystemClock; import java.util.HashSet; import java.util.Optional; @@ -127,6 +127,7 @@ public class UdfpsController implements DozeReceiver { @Nullable private final UdfpsHbmProvider mHbmProvider; @NonNull private final KeyguardBypassController mKeyguardBypassController; @NonNull private final ConfigurationController mConfigurationController; + @NonNull private final SystemClock mSystemClock; @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @@ -165,7 +166,8 @@ public class UdfpsController implements DozeReceiver { public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) + // vibration will bypass battery saver mode: + .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY) .build(); public static final VibrationEffect EFFECT_CLICK = @@ -213,14 +215,12 @@ public class UdfpsController implements DozeReceiver { } void onAcquiredGood() { - Log.d(TAG, "onAcquiredGood"); if (mEnrollHelper != null) { mEnrollHelper.animateIfLastStep(); } } void onEnrollmentHelp() { - Log.d(TAG, "onEnrollmentHelp"); if (mEnrollHelper != null) { mEnrollHelper.onEnrollmentHelp(); } @@ -454,19 +454,19 @@ public class UdfpsController implements DozeReceiver { final String touchInfo = String.format( "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b", minor, major, v, exceedsVelocityThreshold); - final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime; + final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime; if (!isIlluminationRequested && !mGoodCaptureReceived && !exceedsVelocityThreshold) { onFingerDown((int) event.getRawX(), (int) event.getRawY(), minor, major); Log.v(TAG, "onTouch | finger down: " + touchInfo); - mTouchLogTime = SystemClock.elapsedRealtime(); - mPowerManager.userActivity(SystemClock.uptimeMillis(), + mTouchLogTime = mSystemClock.elapsedRealtime(); + mPowerManager.userActivity(mSystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); handled = true; } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) { Log.v(TAG, "onTouch | finger move: " + touchInfo); - mTouchLogTime = SystemClock.elapsedRealtime(); + mTouchLogTime = mSystemClock.elapsedRealtime(); } } else { Log.v(TAG, "onTouch | finger outside"); @@ -530,7 +530,8 @@ public class UdfpsController implements DozeReceiver { @NonNull KeyguardBypassController keyguardBypassController, @NonNull DisplayManager displayManager, @Main Handler mainHandler, - @NonNull ConfigurationController configurationController) { + @NonNull ConfigurationController configurationController, + @NonNull SystemClock systemClock) { mContext = context; mExecution = execution; // TODO (b/185124905): inject main handler and vibrator once done prototyping @@ -566,6 +567,7 @@ public class UdfpsController implements DozeReceiver { mainHandler); mKeyguardBypassController = keyguardBypassController; mConfigurationController = configurationController; + mSystemClock = systemClock; mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists @@ -708,15 +710,21 @@ public class UdfpsController implements DozeReceiver { return mCoreLayoutParams; } + private void onOrientationChanged() { // When the configuration changes it's almost always necessary to destroy and re-create // the overlay's window to pass it the new LayoutParams. // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless // of whether it is already hidden. + final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth(); hideUdfpsOverlay(); + // If the overlay needs to be shown, this will re-create and show the overlay with the // updated LayoutParams. Otherwise, the overlay will remain hidden. updateOverlay(); + if (wasShowingAltAuth) { + mKeyguardViewManager.showGenericBouncer(true); + } } private void showUdfpsOverlay(@NonNull ServerRequest request) { @@ -787,6 +795,7 @@ public class UdfpsController implements DozeReceiver { mKeyguardViewMediator, mLockscreenShadeTransitionController, mConfigurationController, + mSystemClock, mKeyguardStateController, this ); @@ -823,10 +832,14 @@ public class UdfpsController implements DozeReceiver { Log.v(TAG, "hideUdfpsOverlay | removing window"); // Reset the controller back to its starting state. onFingerUp(); + boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth(); mWindowManager.removeView(mView); mView.setOnTouchListener(null); mView.setOnHoverListener(null); mView.setAnimationViewController(null); + if (wasShowingAltAuth) { + mKeyguardViewManager.resetAlternateAuth(true); + } mAccessibilityManager.removeTouchExplorationStateChangeListener( mTouchExplorationStateChangeListener); mView = null; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java index 2034ff35be70..d4077563cfea 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java @@ -16,11 +16,9 @@ package com.android.systemui.biometrics; -import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Context; -import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -28,17 +26,11 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Looper; -import android.util.TypedValue; import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.LinearInterpolator; -import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.internal.graphics.ColorUtils; import com.android.systemui.R; /** @@ -47,20 +39,10 @@ import com.android.systemui.R; public class UdfpsEnrollDrawable extends UdfpsDrawable { private static final String TAG = "UdfpsAnimationEnroll"; - private static final long HINT_COLOR_ANIM_DELAY_MS = 233L; - private static final long HINT_COLOR_ANIM_DURATION_MS = 517L; - private static final long HINT_WIDTH_ANIM_DURATION_MS = 233L; - private static final long TARGET_ANIM_DURATION_LONG = 800L; - private static final long TARGET_ANIM_DURATION_SHORT = 600L; + private static final long ANIM_DURATION = 800; // 1 + SCALE_MAX is the maximum that the moving target will animate to private static final float SCALE_MAX = 0.25f; - private static final float HINT_PADDING_DP = 10f; - private static final float HINT_MAX_WIDTH_DP = 6f; - private static final float HINT_ANGLE = 40f; - - private final Handler mHandler = new Handler(Looper.getMainLooper()); - @NonNull private final Drawable mMovingTargetFpIcon; @NonNull private final Paint mSensorOutlinePaint; @NonNull private final Paint mBlueFill; @@ -69,41 +51,17 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { @Nullable private UdfpsEnrollHelper mEnrollHelper; // Moving target animator set - @Nullable AnimatorSet mTargetAnimatorSet; + @Nullable AnimatorSet mAnimatorSet; // Moving target location float mCurrentX; float mCurrentY; // Moving target size float mCurrentScale = 1.f; - @ColorInt private final int mHintColorFaded; - @ColorInt private final int mHintColorHighlight; - private final float mHintMaxWidthPx; - private final float mHintPaddingPx; - - @NonNull private final Animator.AnimatorListener mTargetAnimListener; - - private boolean mShouldShowTipHint = false; - @NonNull private final Paint mTipHintPaint; - @Nullable private AnimatorSet mTipHintAnimatorSet; - @Nullable private ValueAnimator mTipHintColorAnimator; - @Nullable private ValueAnimator mTipHintWidthAnimator; - @NonNull private final ValueAnimator.AnimatorUpdateListener mTipHintColorUpdateListener; - @NonNull private final ValueAnimator.AnimatorUpdateListener mTipHintWidthUpdateListener; - @NonNull private final Animator.AnimatorListener mTipHintPulseListener; - - private boolean mShouldShowEdgeHint = false; - @NonNull private final Paint mEdgeHintPaint; - @Nullable private AnimatorSet mEdgeHintAnimatorSet; - @Nullable private ValueAnimator mEdgeHintColorAnimator; - @Nullable private ValueAnimator mEdgeHintWidthAnimator; - @NonNull private final ValueAnimator.AnimatorUpdateListener mEdgeHintColorUpdateListener; - @NonNull private final ValueAnimator.AnimatorUpdateListener mEdgeHintWidthUpdateListener; - @NonNull private final Animator.AnimatorListener mEdgeHintPulseListener; - UdfpsEnrollDrawable(@NonNull Context context) { super(context); + mSensorOutlinePaint = new Paint(0 /* flags */); mSensorOutlinePaint.setAntiAlias(true); mSensorOutlinePaint.setColor(mContext.getColor(R.color.udfps_enroll_icon)); @@ -120,117 +78,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { mMovingTargetFpIcon.mutate(); mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon)); - - mHintColorFaded = getHintColorFaded(context); - mHintColorHighlight = context.getColor(R.color.udfps_enroll_progress); - mHintMaxWidthPx = Utils.dpToPixels(context, HINT_MAX_WIDTH_DP); - mHintPaddingPx = Utils.dpToPixels(context, HINT_PADDING_DP); - - mTargetAnimListener = new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) {} - - @Override - public void onAnimationEnd(Animator animation) { - updateTipHintVisibility(); - } - - @Override - public void onAnimationCancel(Animator animation) {} - - @Override - public void onAnimationRepeat(Animator animation) {} - }; - - mTipHintPaint = new Paint(0 /* flags */); - mTipHintPaint.setAntiAlias(true); - mTipHintPaint.setColor(mHintColorFaded); - mTipHintPaint.setStyle(Paint.Style.STROKE); - mTipHintPaint.setStrokeCap(Paint.Cap.ROUND); - mTipHintPaint.setStrokeWidth(0f); - mTipHintColorUpdateListener = animation -> { - mTipHintPaint.setColor((int) animation.getAnimatedValue()); - invalidateSelf(); - }; - mTipHintWidthUpdateListener = animation -> { - mTipHintPaint.setStrokeWidth((float) animation.getAnimatedValue()); - invalidateSelf(); - }; - mTipHintPulseListener = new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) {} - - @Override - public void onAnimationEnd(Animator animation) { - mHandler.postDelayed(() -> { - mTipHintColorAnimator = - ValueAnimator.ofArgb(mTipHintPaint.getColor(), mHintColorFaded); - mTipHintColorAnimator.setInterpolator(new LinearInterpolator()); - mTipHintColorAnimator.setDuration(HINT_COLOR_ANIM_DURATION_MS); - mTipHintColorAnimator.addUpdateListener(mTipHintColorUpdateListener); - mTipHintColorAnimator.start(); - }, HINT_COLOR_ANIM_DELAY_MS); - } - - @Override - public void onAnimationCancel(Animator animation) {} - - @Override - public void onAnimationRepeat(Animator animation) {} - }; - - mEdgeHintPaint = new Paint(0 /* flags */); - mEdgeHintPaint.setAntiAlias(true); - mEdgeHintPaint.setColor(mHintColorFaded); - mEdgeHintPaint.setStyle(Paint.Style.STROKE); - mEdgeHintPaint.setStrokeCap(Paint.Cap.ROUND); - mEdgeHintPaint.setStrokeWidth(0f); - mEdgeHintColorUpdateListener = animation -> { - mEdgeHintPaint.setColor((int) animation.getAnimatedValue()); - invalidateSelf(); - }; - mEdgeHintWidthUpdateListener = animation -> { - mEdgeHintPaint.setStrokeWidth((float) animation.getAnimatedValue()); - invalidateSelf(); - }; - mEdgeHintPulseListener = new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) {} - - @Override - public void onAnimationEnd(Animator animation) { - mHandler.postDelayed(() -> { - mEdgeHintColorAnimator = - ValueAnimator.ofArgb(mEdgeHintPaint.getColor(), mHintColorFaded); - mEdgeHintColorAnimator.setInterpolator(new LinearInterpolator()); - mEdgeHintColorAnimator.setDuration(HINT_COLOR_ANIM_DURATION_MS); - mEdgeHintColorAnimator.addUpdateListener(mEdgeHintColorUpdateListener); - mEdgeHintColorAnimator.start(); - }, HINT_COLOR_ANIM_DELAY_MS); - } - - @Override - public void onAnimationCancel(Animator animation) {} - - @Override - public void onAnimationRepeat(Animator animation) {} - }; - } - - @ColorInt - private static int getHintColorFaded(@NonNull Context context) { - final TypedValue tv = new TypedValue(); - context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, tv, true); - final int alpha = (int) (tv.getFloat() * 255f); - - final int[] attrs = new int[] {android.R.attr.colorControlNormal}; - final TypedArray ta = context.obtainStyledAttributes(attrs); - try { - @ColorInt final int color = ta.getColor(0, context.getColor(R.color.white_disabled)); - return ColorUtils.setAlphaComponent(color, alpha); - } finally { - ta.recycle(); - } } void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) { @@ -251,154 +98,41 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { } void onEnrollmentProgress(int remaining, int totalSteps) { - if (mEnrollHelper == null) { - return; - } - - if (!mEnrollHelper.isCenterEnrollmentStage()) { - if (mTargetAnimatorSet != null && mTargetAnimatorSet.isRunning()) { - mTargetAnimatorSet.end(); + if (mEnrollHelper.isCenterEnrollmentComplete()) { + if (mAnimatorSet != null && mAnimatorSet.isRunning()) { + mAnimatorSet.end(); } final PointF point = mEnrollHelper.getNextGuidedEnrollmentPoint(); - if (mCurrentX != point.x || mCurrentY != point.y) { - final ValueAnimator x = ValueAnimator.ofFloat(mCurrentX, point.x); - x.addUpdateListener(animation -> { - mCurrentX = (float) animation.getAnimatedValue(); - invalidateSelf(); - }); - - final ValueAnimator y = ValueAnimator.ofFloat(mCurrentY, point.y); - y.addUpdateListener(animation -> { - mCurrentY = (float) animation.getAnimatedValue(); - invalidateSelf(); - }); - - final boolean isMovingToCenter = point.x == 0f && point.y == 0f; - final long duration = isMovingToCenter - ? TARGET_ANIM_DURATION_SHORT - : TARGET_ANIM_DURATION_LONG; - - final ValueAnimator scale = ValueAnimator.ofFloat(0, (float) Math.PI); - scale.setDuration(duration); - scale.addUpdateListener(animation -> { - // Grow then shrink - mCurrentScale = 1 - + SCALE_MAX * (float) Math.sin((float) animation.getAnimatedValue()); - invalidateSelf(); - }); - mTargetAnimatorSet = new AnimatorSet(); - - mTargetAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); - mTargetAnimatorSet.setDuration(duration); - mTargetAnimatorSet.addListener(mTargetAnimListener); - mTargetAnimatorSet.playTogether(x, y, scale); - mTargetAnimatorSet.start(); - } else { - updateTipHintVisibility(); - } - } else { - updateTipHintVisibility(); + final ValueAnimator x = ValueAnimator.ofFloat(mCurrentX, point.x); + x.addUpdateListener(animation -> { + mCurrentX = (float) animation.getAnimatedValue(); + invalidateSelf(); + }); + + final ValueAnimator y = ValueAnimator.ofFloat(mCurrentY, point.y); + y.addUpdateListener(animation -> { + mCurrentY = (float) animation.getAnimatedValue(); + invalidateSelf(); + }); + + final ValueAnimator scale = ValueAnimator.ofFloat(0, (float) Math.PI); + scale.setDuration(ANIM_DURATION); + scale.addUpdateListener(animation -> { + // Grow then shrink + mCurrentScale = 1 + + SCALE_MAX * (float) Math.sin((float) animation.getAnimatedValue()); + invalidateSelf(); + }); + + mAnimatorSet = new AnimatorSet(); + + mAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); + mAnimatorSet.setDuration(ANIM_DURATION); + mAnimatorSet.playTogether(x, y, scale); + mAnimatorSet.start(); } - - updateEdgeHintVisibility(); - } - - private void updateTipHintVisibility() { - final boolean shouldShow = mEnrollHelper != null && mEnrollHelper.isTipEnrollmentStage(); - if (mShouldShowTipHint == shouldShow) { - return; - } - mShouldShowTipHint = shouldShow; - - if (mTipHintWidthAnimator != null && mTipHintWidthAnimator.isRunning()) { - mTipHintWidthAnimator.cancel(); - } - - final float targetWidth = shouldShow ? mHintMaxWidthPx : 0f; - mTipHintWidthAnimator = ValueAnimator.ofFloat(mTipHintPaint.getStrokeWidth(), targetWidth); - mTipHintWidthAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS); - mTipHintWidthAnimator.addUpdateListener(mTipHintWidthUpdateListener); - - if (shouldShow) { - startTipHintPulseAnimation(); - } else { - mTipHintWidthAnimator.start(); - } - } - - private void updateEdgeHintVisibility() { - final boolean shouldShow = mEnrollHelper != null && mEnrollHelper.isEdgeEnrollmentStage(); - if (mShouldShowEdgeHint == shouldShow) { - return; - } - mShouldShowEdgeHint = shouldShow; - - if (mEdgeHintWidthAnimator != null && mEdgeHintWidthAnimator.isRunning()) { - mEdgeHintWidthAnimator.cancel(); - } - - final float targetWidth = shouldShow ? mHintMaxWidthPx : 0f; - mEdgeHintWidthAnimator = - ValueAnimator.ofFloat(mEdgeHintPaint.getStrokeWidth(), targetWidth); - mEdgeHintWidthAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS); - mEdgeHintWidthAnimator.addUpdateListener(mEdgeHintWidthUpdateListener); - - if (shouldShow) { - startEdgeHintPulseAnimation(); - } else { - mEdgeHintWidthAnimator.start(); - } - } - - private void startTipHintPulseAnimation() { - mHandler.removeCallbacksAndMessages(null); - if (mTipHintAnimatorSet != null && mTipHintAnimatorSet.isRunning()) { - mTipHintAnimatorSet.cancel(); - } - if (mTipHintColorAnimator != null && mTipHintColorAnimator.isRunning()) { - mTipHintColorAnimator.cancel(); - } - - mTipHintColorAnimator = ValueAnimator.ofArgb(mTipHintPaint.getColor(), mHintColorHighlight); - mTipHintColorAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS); - mTipHintColorAnimator.addUpdateListener(mTipHintColorUpdateListener); - mTipHintColorAnimator.addListener(mTipHintPulseListener); - - mTipHintAnimatorSet = new AnimatorSet(); - mTipHintAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); - mTipHintAnimatorSet.playTogether(mTipHintColorAnimator, mTipHintWidthAnimator); - mTipHintAnimatorSet.start(); - } - - private void startEdgeHintPulseAnimation() { - mHandler.removeCallbacksAndMessages(null); - if (mEdgeHintAnimatorSet != null && mEdgeHintAnimatorSet.isRunning()) { - mEdgeHintAnimatorSet.cancel(); - } - if (mEdgeHintColorAnimator != null && mEdgeHintColorAnimator.isRunning()) { - mEdgeHintColorAnimator.cancel(); - } - - mEdgeHintColorAnimator = - ValueAnimator.ofArgb(mEdgeHintPaint.getColor(), mHintColorHighlight); - mEdgeHintColorAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS); - mEdgeHintColorAnimator.addUpdateListener(mEdgeHintColorUpdateListener); - mEdgeHintColorAnimator.addListener(mEdgeHintPulseListener); - - mEdgeHintAnimatorSet = new AnimatorSet(); - mEdgeHintAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); - mEdgeHintAnimatorSet.playTogether(mEdgeHintColorAnimator, mEdgeHintWidthAnimator); - mEdgeHintAnimatorSet.start(); - } - - private boolean isTipHintVisible() { - return mTipHintPaint.getStrokeWidth() > 0f; - } - - private boolean isEdgeHintVisible() { - return mEdgeHintPaint.getStrokeWidth() > 0f; } @Override @@ -408,7 +142,7 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { } // Draw moving target - if (mEnrollHelper != null && !mEnrollHelper.isCenterEnrollmentStage()) { + if (mEnrollHelper.isCenterEnrollmentComplete()) { canvas.save(); canvas.translate(mCurrentX, mCurrentY); @@ -428,59 +162,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { mFingerprintDrawable.setAlpha(mAlpha); mSensorOutlinePaint.setAlpha(mAlpha); } - - // Draw the finger tip or edges hint. - if (isTipHintVisible() || isEdgeHintVisible()) { - canvas.save(); - - // Make arcs start from the top, rather than the right. - canvas.rotate(-90f, mSensorRect.centerX(), mSensorRect.centerY()); - - final float halfSensorHeight = Math.abs(mSensorRect.bottom - mSensorRect.top) / 2f; - final float halfSensorWidth = Math.abs(mSensorRect.right - mSensorRect.left) / 2f; - final float hintXOffset = halfSensorWidth + mHintPaddingPx; - final float hintYOffset = halfSensorHeight + mHintPaddingPx; - - if (isTipHintVisible()) { - canvas.drawArc( - mSensorRect.centerX() - hintXOffset, - mSensorRect.centerY() - hintYOffset, - mSensorRect.centerX() + hintXOffset, - mSensorRect.centerY() + hintYOffset, - -HINT_ANGLE / 2f, - HINT_ANGLE, - false /* useCenter */, - mTipHintPaint); - } - - if (isEdgeHintVisible()) { - // Draw right edge hint. - canvas.rotate(-90f, mSensorRect.centerX(), mSensorRect.centerY()); - canvas.drawArc( - mSensorRect.centerX() - hintXOffset, - mSensorRect.centerY() - hintYOffset, - mSensorRect.centerX() + hintXOffset, - mSensorRect.centerY() + hintYOffset, - -HINT_ANGLE / 2f, - HINT_ANGLE, - false /* useCenter */, - mEdgeHintPaint); - - // Draw left edge hint. - canvas.rotate(180f, mSensorRect.centerX(), mSensorRect.centerY()); - canvas.drawArc( - mSensorRect.centerX() - hintXOffset, - mSensorRect.centerY() - hintYOffset, - mSensorRect.centerX() + hintXOffset, - mSensorRect.centerY() + hintYOffset, - -HINT_ANGLE / 2f, - HINT_ANGLE, - false /* useCenter */, - mEdgeHintPaint); - } - - canvas.restore(); - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java index 8ac6df7198b7..19148e383005 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java @@ -44,20 +44,13 @@ public class UdfpsEnrollHelper { private static final String NEW_COORDS_OVERRIDE = "com.android.systemui.biometrics.UdfpsNewCoords"; - static final int ENROLL_STAGE_COUNT = 4; - - // TODO(b/198928407): Consolidate with FingerprintEnrollEnrolling - private static final int[] STAGE_THRESHOLDS = new int[] { - 2, // center - 18, // guided - 22, // fingertip - 38, // edges - }; + // Enroll with two center touches before going to guided enrollment + private static final int NUM_CENTER_TOUCHES = 2; interface Listener { void onEnrollmentProgress(int remaining, int totalSteps); - void onEnrollmentHelp(int remaining, int totalSteps); void onLastStepAcquired(); + void onEnrollmentHelp(); } @NonNull private final Context mContext; @@ -73,8 +66,6 @@ public class UdfpsEnrollHelper { // interface makes no promises about monotonically increasing by one each time. private int mLocationsEnrolled = 0; - private int mCenterTouchCount = 0; - @Nullable Listener mListener; public UdfpsEnrollHelper(@NonNull Context context, int reason) { @@ -127,43 +118,17 @@ public class UdfpsEnrollHelper { } } - static int getStageThreshold(int index) { - return STAGE_THRESHOLDS[index]; - } - - static int getLastStageThreshold() { - return STAGE_THRESHOLDS[ENROLL_STAGE_COUNT - 1]; - } - boolean shouldShowProgressBar() { return mEnrollReason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING; } void onEnrollmentProgress(int remaining) { - Log.d(TAG, "onEnrollmentProgress: remaining = " + remaining - + ", mRemainingSteps = " + mRemainingSteps - + ", mTotalSteps = " + mTotalSteps - + ", mLocationsEnrolled = " + mLocationsEnrolled - + ", mCenterTouchCount = " + mCenterTouchCount); - - if (remaining != mRemainingSteps) { - mLocationsEnrolled++; - if (isCenterEnrollmentStage()) { - mCenterTouchCount++; - } - } - if (mTotalSteps == -1) { mTotalSteps = remaining; + } - // Allocate (or subtract) any extra steps for the first enroll stage. - final int extraSteps = mTotalSteps - getLastStageThreshold(); - if (extraSteps != 0) { - for (int stageIndex = 0; stageIndex < ENROLL_STAGE_COUNT; stageIndex++) { - STAGE_THRESHOLDS[stageIndex] = - Math.max(0, STAGE_THRESHOLDS[stageIndex] + extraSteps); - } - } + if (remaining != mRemainingSteps) { + mLocationsEnrolled++; } mRemainingSteps = remaining; @@ -175,7 +140,7 @@ public class UdfpsEnrollHelper { void onEnrollmentHelp() { if (mListener != null) { - mListener.onEnrollmentHelp(mRemainingSteps, mTotalSteps); + mListener.onEnrollmentHelp(); } } @@ -190,39 +155,19 @@ public class UdfpsEnrollHelper { } } - boolean isCenterEnrollmentStage() { + boolean isCenterEnrollmentComplete() { if (mTotalSteps == -1 || mRemainingSteps == -1) { - return true; - } - return mTotalSteps - mRemainingSteps < STAGE_THRESHOLDS[0]; - } - - boolean isGuidedEnrollmentStage() { - if (mAccessibilityEnabled || mTotalSteps == -1 || mRemainingSteps == -1) { return false; - } - final int progressSteps = mTotalSteps - mRemainingSteps; - return progressSteps >= STAGE_THRESHOLDS[0] && progressSteps < STAGE_THRESHOLDS[1]; - } - - boolean isTipEnrollmentStage() { - if (mTotalSteps == -1 || mRemainingSteps == -1) { - return false; - } - final int progressSteps = mTotalSteps - mRemainingSteps; - return progressSteps >= STAGE_THRESHOLDS[1] && progressSteps < STAGE_THRESHOLDS[2]; - } - - boolean isEdgeEnrollmentStage() { - if (mTotalSteps == -1 || mRemainingSteps == -1) { + } else if (mAccessibilityEnabled) { return false; } - return mTotalSteps - mRemainingSteps >= STAGE_THRESHOLDS[2]; + final int stepsEnrolled = mTotalSteps - mRemainingSteps; + return stepsEnrolled >= NUM_CENTER_TOUCHES; } @NonNull PointF getNextGuidedEnrollmentPoint() { - if (mAccessibilityEnabled || !isGuidedEnrollmentStage()) { + if (mAccessibilityEnabled) { return new PointF(0f, 0f); } @@ -232,14 +177,13 @@ public class UdfpsEnrollHelper { SCALE_OVERRIDE, SCALE, UserHandle.USER_CURRENT); } - final int index = mLocationsEnrolled - mCenterTouchCount; + final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES; final PointF originalPoint = mGuidedEnrollmentPoints .get(index % mGuidedEnrollmentPoints.size()); return new PointF(originalPoint.x * scale, originalPoint.y * scale); } void animateIfLastStep() { - Log.d(TAG, "animateIfLastStep: mRemainingSteps = " + mRemainingSteps); if (mListener == null) { Log.e(TAG, "animateIfLastStep, null listener"); return; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java index b56543f4851b..373d17c8ef66 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java @@ -16,107 +16,195 @@ package com.android.systemui.biometrics; +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.annotation.ColorInt; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.Log; +import android.util.TypedValue; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; +import com.android.systemui.R; /** * UDFPS enrollment progress bar. */ public class UdfpsEnrollProgressBarDrawable extends Drawable { - private static final String TAG = "UdfpsProgressBar"; - private static final float SEGMENT_GAP_ANGLE = 12f; + private static final String TAG = "UdfpsEnrollProgressBarDrawable"; - @NonNull private final List<UdfpsEnrollProgressBarSegment> mSegments; + private static final float PROGRESS_BAR_THICKNESS_DP = 12; + + @NonNull private final Context mContext; + @NonNull private final Paint mBackgroundCirclePaint; + @NonNull private final Paint mProgressPaint; + + @Nullable private ValueAnimator mProgressAnimator; + @Nullable private ValueAnimator mProgressShowingHelpAnimator; + @Nullable private ValueAnimator mProgressHidingHelpAnimator; + @ColorInt private final int mProgressColor; + @ColorInt private final int mProgressHelpColor; + private final int mShortAnimationDuration; + private float mProgress; + private int mRotation; // After last step, rotate the progress bar once + private boolean mLastStepAcquired; public UdfpsEnrollProgressBarDrawable(@NonNull Context context) { - mSegments = new ArrayList<>(UdfpsEnrollHelper.ENROLL_STAGE_COUNT); - float startAngle = SEGMENT_GAP_ANGLE / 2f; - final float sweepAngle = (360f / UdfpsEnrollHelper.ENROLL_STAGE_COUNT) - SEGMENT_GAP_ANGLE; - final Runnable invalidateRunnable = this::invalidateSelf; - for (int index = 0; index < UdfpsEnrollHelper.ENROLL_STAGE_COUNT; index++) { - mSegments.add(new UdfpsEnrollProgressBarSegment(context, getBounds(), startAngle, - sweepAngle, SEGMENT_GAP_ANGLE, invalidateRunnable)); - startAngle += sweepAngle + SEGMENT_GAP_ANGLE; - } + mContext = context; + + mShortAnimationDuration = context.getResources() + .getInteger(com.android.internal.R.integer.config_shortAnimTime); + mProgressColor = context.getColor(R.color.udfps_enroll_progress); + mProgressHelpColor = context.getColor(R.color.udfps_enroll_progress_help); + + mBackgroundCirclePaint = new Paint(); + mBackgroundCirclePaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP)); + mBackgroundCirclePaint.setColor(context.getColor(R.color.white_disabled)); + mBackgroundCirclePaint.setAntiAlias(true); + mBackgroundCirclePaint.setStyle(Paint.Style.STROKE); + + // Background circle color + alpha + TypedArray tc = context.obtainStyledAttributes( + new int[] {android.R.attr.colorControlNormal}); + int tintColor = tc.getColor(0, mBackgroundCirclePaint.getColor()); + mBackgroundCirclePaint.setColor(tintColor); + tc.recycle(); + TypedValue alpha = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true); + mBackgroundCirclePaint.setAlpha((int) (alpha.getFloat() * 255)); + + // Progress should not be color extracted + mProgressPaint = new Paint(); + mProgressPaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP)); + mProgressPaint.setColor(mProgressColor); + mProgressPaint.setAntiAlias(true); + mProgressPaint.setStyle(Paint.Style.STROKE); + mProgressPaint.setStrokeCap(Paint.Cap.ROUND); } void setEnrollmentProgress(int remaining, int totalSteps) { - if (remaining == totalSteps) { - // Show some progress for the initial touch. - setEnrollmentProgress(1); - } else { - setEnrollmentProgress(totalSteps - remaining); - } + // Add one so that the first steps actually changes progress, but also so that the last + // step ends at 1.0 + final float progress = (totalSteps - remaining + 1) / (float) (totalSteps + 1); + setEnrollmentProgress(progress); } - private void setEnrollmentProgress(int progressSteps) { - Log.d(TAG, "setEnrollmentProgress: progressSteps = " + progressSteps); - - int segmentIndex = 0; - int prevThreshold = 0; - while (segmentIndex < mSegments.size()) { - final UdfpsEnrollProgressBarSegment segment = mSegments.get(segmentIndex); - final int threshold = UdfpsEnrollHelper.getStageThreshold(segmentIndex); - - if (progressSteps >= threshold && !segment.isFilledOrFilling()) { - Log.d(TAG, "setEnrollmentProgress: segment[" + segmentIndex + "] complete"); - segment.updateProgress(1f); - break; - } else if (progressSteps >= prevThreshold && progressSteps < threshold) { - final int relativeSteps = progressSteps - prevThreshold; - final int relativeThreshold = threshold - prevThreshold; - final float segmentProgress = (float) relativeSteps / (float) relativeThreshold; - Log.d(TAG, "setEnrollmentProgress: segment[" + segmentIndex + "] progress = " - + segmentProgress); - segment.updateProgress(segmentProgress); - break; - } - - segmentIndex++; - prevThreshold = threshold; + private void setEnrollmentProgress(float progress) { + if (mLastStepAcquired) { + return; } - if (progressSteps >= UdfpsEnrollHelper.getLastStageThreshold()) { - Log.d(TAG, "setEnrollmentProgress: startCompletionAnimation"); - for (final UdfpsEnrollProgressBarSegment segment : mSegments) { - segment.startCompletionAnimation(); - } - } else { - Log.d(TAG, "setEnrollmentProgress: cancelCompletionAnimation"); - for (final UdfpsEnrollProgressBarSegment segment : mSegments) { - segment.cancelCompletionAnimation(); - } + long animationDuration = mShortAnimationDuration; + + hideEnrollmentHelp(); + + if (progress == 1.f) { + animationDuration = 400; + final ValueAnimator rotationAnimator = ValueAnimator.ofInt(0, 400); + rotationAnimator.setDuration(animationDuration); + rotationAnimator.addUpdateListener(animation -> { + Log.d(TAG, "Rotation: " + mRotation); + mRotation = (int) animation.getAnimatedValue(); + invalidateSelf(); + }); + rotationAnimator.start(); } + + if (mProgressAnimator != null && mProgressAnimator.isRunning()) { + mProgressAnimator.cancel(); + } + + mProgressAnimator = ValueAnimator.ofFloat(mProgress, progress); + mProgressAnimator.setDuration(animationDuration); + mProgressAnimator.addUpdateListener(animation -> { + mProgress = (float) animation.getAnimatedValue(); + invalidateSelf(); + }); + mProgressAnimator.start(); } void onLastStepAcquired() { - Log.d(TAG, "setEnrollmentProgress: onLastStepAcquired"); - setEnrollmentProgress(UdfpsEnrollHelper.getLastStageThreshold()); + setEnrollmentProgress(1.f); + mLastStepAcquired = true; + } + + void onEnrollmentHelp() { + if (mProgressShowingHelpAnimator != null || mProgressAnimator == null) { + return; // already showing or at 0% (no progress bar visible) + } + + if (mProgressHidingHelpAnimator != null && mProgressHidingHelpAnimator.isRunning()) { + mProgressHidingHelpAnimator.cancel(); + } + mProgressHidingHelpAnimator = null; + + mProgressShowingHelpAnimator = getProgressColorAnimator( + mProgressPaint.getColor(), mProgressHelpColor); + mProgressShowingHelpAnimator.start(); + } + + private void hideEnrollmentHelp() { + if (mProgressHidingHelpAnimator != null || mProgressShowingHelpAnimator == null) { + return; // already hidden or help never shown + } + + if (mProgressShowingHelpAnimator != null && mProgressShowingHelpAnimator.isRunning()) { + mProgressShowingHelpAnimator.cancel(); + } + mProgressShowingHelpAnimator = null; + + mProgressHidingHelpAnimator = getProgressColorAnimator( + mProgressPaint.getColor(), mProgressColor); + mProgressHidingHelpAnimator.start(); + } + + private ValueAnimator getProgressColorAnimator(@ColorInt int from, @ColorInt int to) { + final ValueAnimator animator = ValueAnimator.ofObject( + ArgbEvaluator.getInstance(), from, to); + animator.setDuration(mShortAnimationDuration); + animator.addUpdateListener(animation -> { + mProgressPaint.setColor((int) animation.getAnimatedValue()); + }); + return animator; } @Override public void draw(@NonNull Canvas canvas) { - Log.d(TAG, "setEnrollmentProgress: draw"); - canvas.save(); // Progress starts from the top, instead of the right - canvas.rotate(-90f, getBounds().centerX(), getBounds().centerY()); - - // Draw each of the enroll segments. - for (final UdfpsEnrollProgressBarSegment segment : mSegments) { - segment.draw(canvas); - } + canvas.rotate(-90 + mRotation, getBounds().centerX(), getBounds().centerY()); + + // Progress bar "background track" + final float halfPaddingPx = Utils.dpToPixels(mContext, PROGRESS_BAR_THICKNESS_DP) / 2; + canvas.drawArc(halfPaddingPx, + halfPaddingPx, + getBounds().right - halfPaddingPx, + getBounds().bottom - halfPaddingPx, + 0, + 360, + false, + mBackgroundCirclePaint + ); + + final float progress = 360.f * mProgress; + // Progress + canvas.drawArc(halfPaddingPx, + halfPaddingPx, + getBounds().right - halfPaddingPx, + getBounds().bottom - halfPaddingPx, + 0, + progress, + false, + mProgressPaint + ); canvas.restore(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java deleted file mode 100644 index 5f24380b6ce3..000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.biometrics; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.util.TypedValue; - -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.systemui.R; - -/** - * A single segment of the UDFPS enrollment progress bar. - */ -public class UdfpsEnrollProgressBarSegment { - private static final String TAG = "UdfpsProgressBarSegment"; - - private static final long PROGRESS_ANIMATION_DURATION_MS = 400L; - private static final long OVER_SWEEP_ANIMATION_DELAY_MS = 200L; - private static final long OVER_SWEEP_ANIMATION_DURATION_MS = 200L; - - private static final float STROKE_WIDTH_DP = 12f; - - private final Handler mHandler = new Handler(Looper.getMainLooper()); - - @NonNull private final Rect mBounds; - @NonNull private final Runnable mInvalidateRunnable; - private final float mStartAngle; - private final float mSweepAngle; - private final float mMaxOverSweepAngle; - private final float mStrokeWidthPx; - - @NonNull private final Paint mBackgroundPaint; - @NonNull private final Paint mProgressPaint; - - private boolean mIsFilledOrFilling = false; - - private float mProgress = 0f; - @Nullable private ValueAnimator mProgressAnimator; - @NonNull private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener; - - private float mOverSweepAngle = 0f; - @Nullable private ValueAnimator mOverSweepAnimator; - @Nullable private ValueAnimator mOverSweepReverseAnimator; - @NonNull private final ValueAnimator.AnimatorUpdateListener mOverSweepUpdateListener; - @NonNull private final Runnable mOverSweepAnimationRunnable; - - public UdfpsEnrollProgressBarSegment(@NonNull Context context, @NonNull Rect bounds, - float startAngle, float sweepAngle, float maxOverSweepAngle, - @NonNull Runnable invalidateRunnable) { - - mBounds = bounds; - mInvalidateRunnable = invalidateRunnable; - mStartAngle = startAngle; - mSweepAngle = sweepAngle; - mMaxOverSweepAngle = maxOverSweepAngle; - mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP); - - mBackgroundPaint = new Paint(); - mBackgroundPaint.setStrokeWidth(mStrokeWidthPx); - mBackgroundPaint.setColor(context.getColor(R.color.white_disabled)); - mBackgroundPaint.setAntiAlias(true); - mBackgroundPaint.setStyle(Paint.Style.STROKE); - mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); - - // Background paint color + alpha - final int[] attrs = new int[] {android.R.attr.colorControlNormal}; - final TypedArray ta = context.obtainStyledAttributes(attrs); - @ColorInt final int tintColor = ta.getColor(0, mBackgroundPaint.getColor()); - mBackgroundPaint.setColor(tintColor); - ta.recycle(); - TypedValue alpha = new TypedValue(); - context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true); - mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f)); - - // Progress should not be color extracted - mProgressPaint = new Paint(); - mProgressPaint.setStrokeWidth(mStrokeWidthPx); - mProgressPaint.setColor(context.getColor(R.color.udfps_enroll_progress)); - mProgressPaint.setAntiAlias(true); - mProgressPaint.setStyle(Paint.Style.STROKE); - mProgressPaint.setStrokeCap(Paint.Cap.ROUND); - - mProgressUpdateListener = animation -> { - mProgress = (float) animation.getAnimatedValue(); - mInvalidateRunnable.run(); - }; - - mOverSweepUpdateListener = animation -> { - mOverSweepAngle = (float) animation.getAnimatedValue(); - mInvalidateRunnable.run(); - }; - mOverSweepAnimationRunnable = () -> { - if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) { - mOverSweepAnimator.cancel(); - } - mOverSweepAnimator = ValueAnimator.ofFloat(mOverSweepAngle, mMaxOverSweepAngle); - mOverSweepAnimator.setDuration(OVER_SWEEP_ANIMATION_DURATION_MS); - mOverSweepAnimator.addUpdateListener(mOverSweepUpdateListener); - mOverSweepAnimator.start(); - }; - } - - /** - * Draws this segment to the given canvas. - */ - public void draw(@NonNull Canvas canvas) { - Log.d(TAG, "draw: mProgress = " + mProgress); - - final float halfPaddingPx = mStrokeWidthPx / 2f; - - if (mProgress < 1f) { - // Draw the unfilled background color of the segment. - canvas.drawArc( - halfPaddingPx, - halfPaddingPx, - mBounds.right - halfPaddingPx, - mBounds.bottom - halfPaddingPx, - mStartAngle, - mSweepAngle, - false /* useCenter */, - mBackgroundPaint); - } - - if (mProgress > 0f) { - // Draw the filled progress portion of the segment. - canvas.drawArc( - halfPaddingPx, - halfPaddingPx, - mBounds.right - halfPaddingPx, - mBounds.bottom - halfPaddingPx, - mStartAngle, - mSweepAngle * mProgress + mOverSweepAngle, - false /* useCenter */, - mProgressPaint); - } - } - - /** - * @return Whether this segment is filled or in the process of being filled. - */ - public boolean isFilledOrFilling() { - return mIsFilledOrFilling; - } - - /** - * Updates the fill progress of this segment, animating if necessary. - * - * @param progress The new fill progress, in the range [0, 1]. - */ - public void updateProgress(float progress) { - updateProgress(progress, PROGRESS_ANIMATION_DURATION_MS); - } - - private void updateProgress(float progress, long animationDurationMs) { - Log.d(TAG, "updateProgress: progress = " + progress - + ", duration = " + animationDurationMs); - - if (mProgress == progress) { - Log.d(TAG, "updateProgress skipped: progress == mProgress"); - return; - } - - mIsFilledOrFilling = progress >= 1f; - - if (mProgressAnimator != null && mProgressAnimator.isRunning()) { - mProgressAnimator.cancel(); - } - - mProgressAnimator = ValueAnimator.ofFloat(mProgress, progress); - mProgressAnimator.setDuration(animationDurationMs); - mProgressAnimator.addUpdateListener(mProgressUpdateListener); - mProgressAnimator.start(); - } - - /** - * Queues and runs the completion animation for this segment. - */ - public void startCompletionAnimation() { - final boolean hasCallback = mHandler.hasCallbacks(mOverSweepAnimationRunnable); - if (hasCallback || mOverSweepAngle >= mMaxOverSweepAngle) { - Log.d(TAG, "startCompletionAnimation skipped: hasCallback = " + hasCallback - + ", mOverSweepAngle = " + mOverSweepAngle); - return; - } - - Log.d(TAG, "startCompletionAnimation: mProgress = " + mProgress - + ", mOverSweepAngle = " + mOverSweepAngle); - - // Reset sweep angle back to zero if the animation is being rolled back. - if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) { - mOverSweepReverseAnimator.cancel(); - mOverSweepAngle = 0f; - } - - // Start filling the segment if it isn't already. - if (mProgress < 1f) { - updateProgress(1f, OVER_SWEEP_ANIMATION_DELAY_MS); - } - - // Queue the animation to run after fill completes. - mHandler.postDelayed(mOverSweepAnimationRunnable, OVER_SWEEP_ANIMATION_DELAY_MS); - } - - /** - * Cancels (and reverses, if necessary) a queued or running completion animation. - */ - public void cancelCompletionAnimation() { - Log.d(TAG, "cancelCompletionAnimation: mProgress = " + mProgress - + ", mOverSweepAngle = " + mOverSweepAngle); - - // Cancel the animation if it's queued or running. - mHandler.removeCallbacks(mOverSweepAnimationRunnable); - if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) { - mOverSweepAnimator.cancel(); - } - - // Roll back the animation if it has at least partially run. - if (mOverSweepAngle > 0f) { - if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) { - mOverSweepReverseAnimator.cancel(); - } - - final float completion = mOverSweepAngle / mMaxOverSweepAngle; - final long proratedDuration = (long) (OVER_SWEEP_ANIMATION_DURATION_MS * completion); - mOverSweepReverseAnimator = ValueAnimator.ofFloat(mOverSweepAngle, 0f); - mOverSweepReverseAnimator.setDuration(proratedDuration); - mOverSweepReverseAnimator.addUpdateListener(mOverSweepUpdateListener); - mOverSweepReverseAnimator.start(); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java index 6f02c64e4cf7..d9edef48b3d4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java @@ -83,14 +83,13 @@ public class UdfpsEnrollView extends UdfpsAnimationView { }); } - void onEnrollmentHelp(int remaining, int totalSteps) { - mHandler.post( - () -> mFingerprintProgressDrawable.setEnrollmentProgress(remaining, totalSteps)); - } - void onLastStepAcquired() { mHandler.post(() -> { mFingerprintProgressDrawable.onLastStepAcquired(); }); } + + void onEnrollmentHelp() { + mHandler.post(mFingerprintProgressDrawable::onEnrollmentHelp); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java index 6cdd1c8b0d4e..61534a5a83d1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java @@ -33,21 +33,21 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp @NonNull private final UdfpsEnrollHelper mEnrollHelper; @NonNull private final UdfpsEnrollHelper.Listener mEnrollHelperListener = new UdfpsEnrollHelper.Listener() { - @Override - public void onEnrollmentProgress(int remaining, int totalSteps) { - mView.onEnrollmentProgress(remaining, totalSteps); - } + @Override + public void onEnrollmentProgress(int remaining, int totalSteps) { + mView.onEnrollmentProgress(remaining, totalSteps); + } - @Override - public void onEnrollmentHelp(int remaining, int totalSteps) { - mView.onEnrollmentHelp(remaining, totalSteps); - } + @Override + public void onLastStepAcquired() { + mView.onLastStepAcquired(); + } - @Override - public void onLastStepAcquired() { - mView.onLastStepAcquired(); - } - }; + @Override + public void onEnrollmentHelp() { + mView.onEnrollmentHelp(); + } + }; protected UdfpsEnrollViewController( @NonNull UdfpsEnrollView view, @@ -79,7 +79,7 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp @NonNull @Override public PointF getTouchTranslation() { - if (!mEnrollHelper.isGuidedEnrollmentStage()) { + if (!mEnrollHelper.isCenterEnrollmentComplete()) { return new PointF(0, 0); } else { return mEnrollHelper.getNextGuidedEnrollmentPoint(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 22d7a3ff44f0..8aa545a2013e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; +import com.android.systemui.util.time.SystemClock; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -51,6 +52,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud @NonNull private final KeyguardViewMediator mKeyguardViewMediator; @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController; @NonNull private final ConfigurationController mConfigurationController; + @NonNull private final SystemClock mSystemClock; @NonNull private final KeyguardStateController mKeyguardStateController; @NonNull private final UdfpsController mUdfpsController; @@ -61,7 +63,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud private int mStatusBarState; private float mTransitionToFullShadeProgress; private float mLastDozeAmount; - + private long mLastUdfpsBouncerShowTime = -1; private float mStatusBarExpansion; private boolean mLaunchTransitionFadingAway; @@ -84,6 +86,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull LockscreenShadeTransitionController transitionController, @NonNull ConfigurationController configurationController, + @NonNull SystemClock systemClock, @NonNull KeyguardStateController keyguardStateController, @NonNull UdfpsController udfpsController) { super(view, statusBarStateController, statusBar, dumpManager); @@ -93,6 +96,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud mKeyguardViewMediator = keyguardViewMediator; mLockScreenShadeTransitionController = transitionController; mConfigurationController = configurationController; + mSystemClock = systemClock; mKeyguardStateController = keyguardStateController; mUdfpsController = udfpsController; } @@ -103,6 +107,12 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud } @Override + public void onInit() { + super.onInit(); + mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); + } + + @Override protected void onViewAttached() { super.onViewAttached(); final float dozeAmount = mStatusBarStateController.getDozeAmount(); @@ -171,6 +181,9 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud boolean udfpsAffordanceWasNotShowing = shouldPauseAuth(); mShowingUdfpsBouncer = show; if (mShowingUdfpsBouncer) { + mLastUdfpsBouncerShowTime = mSystemClock.uptimeMillis(); + } + if (mShowingUdfpsBouncer) { if (udfpsAffordanceWasNotShowing) { mView.animateInUdfpsBouncer(null); } @@ -238,16 +251,25 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud * If we were previously showing the udfps bouncer, hide it and instead show the regular * (pin/pattern/password) bouncer. * - * Does nothing if we weren't previously showing the udfps bouncer. + * Does nothing if we weren't previously showing the UDFPS bouncer. */ private void maybeShowInputBouncer() { - if (mShowingUdfpsBouncer) { + if (mShowingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) { mKeyguardViewManager.showBouncer(true); mKeyguardViewManager.resetAlternateAuth(false); } } /** + * Whether the udfps bouncer has shown for at least 200ms before allowing touches outside + * of the udfps icon area to dismiss the udfps bouncer and show the pin/pattern/password + * bouncer. + */ + private boolean hasUdfpsBouncerShownWithMinTime() { + return (mSystemClock.uptimeMillis() - mLastUdfpsBouncerShowTime) > 200; + } + + /** * Set the progress we're currently transitioning to the full shade. 0.0f means we're not * transitioning yet, while 1.0f means we've fully dragged down. */ @@ -265,7 +287,9 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud : (int) MathUtils.constrain( MathUtils.map(.5f, .9f, 0f, 255f, expansion), 0f, 255f); - alpha *= (1.0f - mTransitionToFullShadeProgress); + if (!mShowingUdfpsBouncer) { + alpha *= (1.0f - mTransitionToFullShadeProgress); + } mView.setUnpausedAlpha(alpha); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java index e1349f2aba6d..40c28fab51b8 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java @@ -21,6 +21,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHT import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE; import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER; +import static com.android.systemui.classifier.Classifier.LOCK_ICON; import static com.android.systemui.classifier.Classifier.SHADE_DRAG; import android.graphics.Point; @@ -89,7 +90,9 @@ class ZigZagClassifier extends FalsingClassifier { Result calculateFalsingResult( @Classifier.InteractionType int interactionType, double historyBelief, double historyConfidence) { - if (interactionType == BRIGHTNESS_SLIDER || interactionType == SHADE_DRAG) { + if (interactionType == BRIGHTNESS_SLIDER + || interactionType == SHADE_DRAG + || interactionType == LOCK_ICON) { return Result.passed(0); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index c97a30e6e13e..79ee6a8e8830 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -198,9 +198,11 @@ public class DependencyProvider { @SysUISingleton @Provides static ThemeOverlayApplier provideThemeOverlayManager(Context context, - @Background Executor bgExecutor, OverlayManager overlayManager, + @Background Executor bgExecutor, + @Main Executor mainExecutor, + OverlayManager overlayManager, DumpManager dumpManager) { - return new ThemeOverlayApplier(overlayManager, bgExecutor, + return new ThemeOverlayApplier(overlayManager, bgExecutor, mainExecutor, context.getString(R.string.launcher_overlayable_package), context.getString(R.string.themepicker_overlayable_package), dumpManager); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 470d2f364c1c..98d2739836a9 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -31,6 +31,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.view.Display; +import com.android.systemui.dock.DockManager; import com.android.systemui.doze.dagger.BrightnessSensor; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.doze.dagger.WrappedService; @@ -63,6 +64,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private final Optional<Sensor> mLightSensorOptional; private final WakefulnessLifecycle mWakefulnessLifecycle; private final DozeParameters mDozeParameters; + private final DockManager mDockManager; private final int[] mSensorToBrightness; private final int[] mSensorToScrimOpacity; private final int mScreenBrightnessDim; @@ -87,7 +89,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi @BrightnessSensor Optional<Sensor> lightSensorOptional, DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, WakefulnessLifecycle wakefulnessLifecycle, - DozeParameters dozeParameters) { + DozeParameters dozeParameters, + DockManager dockManager) { mContext = context; mDozeService = service; mSensorManager = sensorManager; @@ -96,6 +99,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi mDozeParameters = dozeParameters; mDozeHost = host; mHandler = handler; + mDockManager = dockManager; mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness; mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness; @@ -122,13 +126,20 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi @Override public void onScreenState(int state) { - if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) { + boolean isDockedScreenOn = state == Display.STATE_ON && mDockManager.isDocked(); + if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND + || (isDockedScreenOn && shouldRegisterLightSensorWhenScreenOnDocked())) { setLightSensorEnabled(true); } else { setLightSensorEnabled(false); } } + private boolean shouldRegisterLightSensorWhenScreenOnDocked() { + return !mDozeParameters.brightnessUsesProx() + || !mDozeParameters.getSelectivelyRegisterSensorsUsingProx(); + } + private void onDestroy() { setLightSensorEnabled(false); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index b2db86f16104..55e6154b829d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -456,13 +456,24 @@ public class DozeSensors { public void updateListening() { if (!mConfigured || mSensor == null) return; - if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting) - && !mRegistered) { - mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); - if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered); + if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) { + if (!mRegistered) { + mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); + if (DEBUG) { + Log.d(TAG, "requestTriggerSensor[" + mSensor + + "] " + mRegistered); + } + } else { + if (DEBUG) { + Log.d(TAG, "requestTriggerSensor[" + mSensor + + "] already registered"); + } + } } else if (mRegistered) { final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor); - if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt); + if (DEBUG) { + Log.d(TAG, "cancelTriggerSensor[" + mSensor + "] " + rt); + } mRegistered = false; } } diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt index bfa478088cad..5b327bd5e4c1 100644 --- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt +++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt @@ -34,7 +34,7 @@ import javax.inject.Inject * See [DumpHandler] for more information on how and when this information is dumped. */ @SysUISingleton -class DumpManager @Inject constructor() { +open class DumpManager @Inject constructor() { private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap() private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap() diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt index 28f63b07e584..6561bd5a5323 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt @@ -25,8 +25,12 @@ import javax.inject.Inject * Proxy to make {@link SystemProperties} easily testable. */ @SysUISingleton -class SystemPropertiesHelper @Inject constructor() { +open class SystemPropertiesHelper @Inject constructor() { fun getBoolean(name: String, default: Boolean): Boolean { return SystemProperties.getBoolean(name, default) } + + fun set(name: String, value: Int) { + SystemProperties.set(name, value.toString()) + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index bc4ced452630..1b4a47e4bf39 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -62,6 +62,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.view.RotationPolicy; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.animation.Interpolators; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -172,7 +173,8 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite SysUiState sysUiState, @Main Handler handler, PackageManager packageManager, - StatusBar statusBar) { + StatusBar statusBar, + KeyguardUpdateMonitor keyguardUpdateMonitor) { super(context, windowManagerFuncs, @@ -204,7 +206,8 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite sysUiState, handler, packageManager, - statusBar); + statusBar, + keyguardUpdateMonitor); mLockPatternUtils = lockPatternUtils; mKeyguardStateController = keyguardStateController; @@ -266,7 +269,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite this::getWalletViewController, mSysuiColorExtractor, mStatusBarService, mNotificationShadeWindowController, mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger(), - getStatusBar()); + getStatusBar(), getKeyguardUpdateMonitor(), mLockPatternUtils); if (shouldShowLockMessage(dialog)) { dialog.showLockMessage(); @@ -334,12 +337,13 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite NotificationShadeWindowController notificationShadeWindowController, SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing, MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger, - StatusBar statusBar) { + StatusBar statusBar, KeyguardUpdateMonitor keyguardUpdateMonitor, + LockPatternUtils lockPatternUtils) { super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions, adapter, overflowAdapter, sysuiColorExtractor, statusBarService, notificationShadeWindowController, sysuiState, onRotateCallback, keyguardShowing, powerAdapter, uiEventLogger, null, - statusBar); + statusBar, keyguardUpdateMonitor, lockPatternUtils); mWalletFactory = walletFactory; // Update window attributes diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index 06e74821869e..9ada54b9ef6f 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -84,6 +84,7 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ImageView.ScaleType; @@ -108,6 +109,7 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.util.ScreenshotHelper; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.MultiListLayout; import com.android.systemui.MultiListLayout.MultiListAdapter; import com.android.systemui.animation.Interpolators; @@ -170,6 +172,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency"; static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot"; + // See NotificationManagerService#scheduleDurationReachedLocked + private static final long TOAST_FADE_TIME = 333; + // See NotificationManagerService.LONG_DELAY + private static final int TOAST_VISIBLE_TIME = 3500; + private final Context mContext; private final GlobalActionsManager mWindowManagerFuncs; private final AudioManager mAudioManager; @@ -231,6 +238,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene protected Handler mMainHandler; private int mSmallestScreenWidthDp; private final StatusBar mStatusBar; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum { @@ -338,7 +346,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene SysUiState sysUiState, @Main Handler handler, PackageManager packageManager, - StatusBar statusBar) { + StatusBar statusBar, + KeyguardUpdateMonitor keyguardUpdateMonitor) { mContext = context; mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; @@ -369,6 +378,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mMainHandler = handler; mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp; mStatusBar = statusBar; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -422,6 +432,10 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene return mStatusBar; } + protected KeyguardUpdateMonitor getKeyguardUpdateMonitor() { + return mKeyguardUpdateMonitor; + } + /** * Show the global actions dialog (creating if necessary) * @@ -653,7 +667,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mAdapter, mOverflowAdapter, mSysuiColorExtractor, mStatusBarService, mNotificationShadeWindowController, mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger, - mInfoProvider, mStatusBar); + mInfoProvider, mStatusBar, mKeyguardUpdateMonitor, mLockPatternUtils); dialog.setOnDismissListener(this); dialog.setOnShowListener(this); @@ -2122,6 +2136,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene private GlobalActionsInfoProvider mInfoProvider; private GestureDetector mGestureDetector; private StatusBar mStatusBar; + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private LockPatternUtils mLockPatternUtils; protected ViewGroup mContainer; @@ -2173,7 +2189,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene NotificationShadeWindowController notificationShadeWindowController, SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing, MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger, - @Nullable GlobalActionsInfoProvider infoProvider, StatusBar statusBar) { + @Nullable GlobalActionsInfoProvider infoProvider, StatusBar statusBar, + KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) { super(context, themeRes); mContext = context; mAdapter = adapter; @@ -2188,6 +2205,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mUiEventLogger = uiEventLogger; mInfoProvider = infoProvider; mStatusBar = statusBar; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mLockPatternUtils = lockPatternUtils; mGestureDetector = new GestureDetector(mContext, mGestureListener); @@ -2308,6 +2327,14 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene if (mInfoProvider != null && mInfoProvider.shouldShowMessage()) { mInfoProvider.addPanel(mContext, mContainer, mAdapter.getCount(), () -> dismiss()); } + + // If user entered from the lock screen and smart lock was enabled, disable it + int user = KeyguardUpdateMonitor.getCurrentUser(); + boolean userHasTrust = mKeyguardUpdateMonitor.getUserHasTrust(user); + if (mKeyguardShowing && userHasTrust) { + mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser()); + showSmartLockDisabledMessage(); + } } protected void fixNavBarClipping() { @@ -2319,6 +2346,37 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene contentParent.setClipToPadding(false); } + private void showSmartLockDisabledMessage() { + // Since power menu is the top window, make a Toast-like view that will show up + View message = LayoutInflater.from(mContext) + .inflate(com.android.systemui.R.layout.global_actions_toast, mContainer, false); + + // Set up animation + AccessibilityManager mAccessibilityManager = + (AccessibilityManager) getContext().getSystemService( + Context.ACCESSIBILITY_SERVICE); + final int visibleTime = mAccessibilityManager.getRecommendedTimeoutMillis( + TOAST_VISIBLE_TIME, AccessibilityManager.FLAG_CONTENT_TEXT); + message.setVisibility(View.VISIBLE); + message.setAlpha(0f); + mContainer.addView(message); + + // Fade in + message.animate() + .alpha(1f) + .setDuration(TOAST_FADE_TIME) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // Then fade out + message.animate() + .alpha(0f) + .setDuration(TOAST_FADE_TIME) + .setStartDelay(visibleTime); + } + }); + } + @Override protected void onStart() { super.onStart(); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 2facf3dedd18..db5dbb0263c8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -212,14 +212,32 @@ class MediaCarouselController @Inject constructor( isSsReactivated: Boolean ) { if (addOrUpdatePlayer(key, oldKey, data)) { + // Log card received if a new resumable media card is added MediaPlayerData.getMediaPlayer(key)?.let { logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED it.mInstanceId, + it.mUid, /* isRecommendationCard */ false, it.surfaceForSmartspaceLogging, rank = MediaPlayerData.getMediaPlayerIndex(key)) } } + if (isSsReactivated) { + // If resumable media is reactivated by headphone connection, update instance + // id for each card and log a receive event. + MediaPlayerData.players().forEachIndexed { index, it -> + if (it.recommendationViewHolder == null) { + it.mInstanceId = SmallHash.hash(it.mUid + + systemClock.currentTimeMillis().toInt()) + logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED + it.mInstanceId, + it.mUid, + /* isRecommendationCard */ false, + it.surfaceForSmartspaceLogging, + rank = index) + } + } + } if (mediaCarouselScrollHandler.visibleToUser && isSsReactivated && !mediaCarouselScrollHandler.qsExpanded) { // It could happen that reactived media player isn't visible to user because @@ -252,6 +270,7 @@ class MediaCarouselController @Inject constructor( MediaPlayerData.getMediaPlayer(key)?.let { logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED it.mInstanceId, + it.mUid, /* isRecommendationCard */ true, it.surfaceForSmartspaceLogging, rank = MediaPlayerData.getMediaPlayerIndex(key)) @@ -261,6 +280,7 @@ class MediaCarouselController @Inject constructor( MediaPlayerData.getMediaPlayerIndex(key)) { logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN it.mInstanceId, + it.mUid, /* isRecommendationCard */ true, it.surfaceForSmartspaceLogging) } @@ -339,9 +359,9 @@ class MediaCarouselController @Inject constructor( if (activeMediaIndex != -1) { previousVisiblePlayerKey?.let { val previousVisibleIndex = MediaPlayerData.playerKeys() - .indexOfFirst { key -> it == key } + .indexOfFirst { key -> it == key } mediaCarouselScrollHandler - .scrollToPlayer(previousVisibleIndex, activeMediaIndex) + .scrollToPlayer(previousVisibleIndex, activeMediaIndex) } ?: { mediaCarouselScrollHandler.scrollToPlayer(destIndex = activeMediaIndex) } @@ -355,11 +375,11 @@ class MediaCarouselController @Inject constructor( MediaPlayerData.moveIfExists(oldKey, key) val existingPlayer = MediaPlayerData.getMediaPlayer(key) val curVisibleMediaKey = MediaPlayerData.playerKeys() - .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) + .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) if (existingPlayer == null) { var newPlayer = mediaControlPanelFactory.get() newPlayer.attachPlayer( - PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) + PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) @@ -407,14 +427,14 @@ class MediaCarouselController @Inject constructor( var newRecs = mediaControlPanelFactory.get() newRecs.attachRecommendation( - RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)) + RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)) newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT) + ViewGroup.LayoutParams.WRAP_CONTENT) newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) newRecs.bindRecommendation(data.copy(backgroundColor = bgColor)) val curVisibleMediaKey = MediaPlayerData.playerKeys() - .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) + .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize, systemClock) updatePlayerToState(newRecs, noAnimation = true) reorderAllPlayers(curVisibleMediaKey) @@ -462,7 +482,7 @@ class MediaCarouselController @Inject constructor( removePlayer(key, dismissMediaData = false, dismissRecommendation = false) smartspaceMediaData?.let { addSmartspaceMediaRecommendations( - it.targetId, it, MediaPlayerData.shouldPrioritizeSs) + it.targetId, it, MediaPlayerData.shouldPrioritizeSs) } } else { removePlayer(key, dismissMediaData = false, dismissRecommendation = false) @@ -585,7 +605,7 @@ class MediaCarouselController @Inject constructor( ?: endShowsActive if (currentlyShowingOnlyActive != endShowsActive || ((currentTransitionProgress != 1.0f && currentTransitionProgress != 0.0f) && - startShowsActive != endShowsActive)) { + startShowsActive != endShowsActive)) { // Whenever we're transitioning from between differing states or the endstate differs // we reset the translation currentlyShowingOnlyActive = endShowsActive @@ -696,23 +716,43 @@ class MediaCarouselController @Inject constructor( } logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN mediaControlPanel.mInstanceId, + mediaControlPanel.mUid, isRecommendationCard, mediaControlPanel.surfaceForSmartspaceLogging) } } @JvmOverloads + /** + * Log Smartspace events + * + * @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN) + * @param instanceId id to uniquely identify a card, e.g. each headphone generates a new + * instanceId + * @param uid uid for the application that media comes from + * @param isRecommendationCard whether the card is media recommendation + * @param surface which display surface the media card is on (e.g. lockscreen, shade) + * @param interactedSubcardRank the rank for interacted media item for recommendation card, -1 + * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc. + * @param interactedSubcardCardinality how many media items were shown to the user when there + * is user interaction + * @param rank the rank for media card in the media carousel, starting from 0 + * + */ fun logSmartspaceCardReported( eventId: Int, instanceId: Int, + uid: Int, isRecommendationCard: Boolean, surface: Int, + interactedSubcardRank: Int = 0, + interactedSubcardCardinality: Int = 0, rank: Int = mediaCarouselScrollHandler.visibleMediaIndex ) { // Only log media resume card when Smartspace data is available if (!isRecommendationCard && - !mediaManager.smartspaceMediaData.isActive && - MediaPlayerData.smartspaceMediaData == null) { + !mediaManager.smartspaceMediaData.isActive && + MediaPlayerData.smartspaceMediaData == null) { return } @@ -720,13 +760,20 @@ class MediaCarouselController @Inject constructor( SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED, eventId, instanceId, - if (isRecommendationCard) - SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS - else - SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_RESUME_MEDIA, + // Deprecated, replaced with AiAi feature type so we don't need to create logging + // card type for each new feature. + SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD, surface, rank, - mediaContent.getChildCount()) + mediaContent.getChildCount(), + if (isRecommendationCard) + 15 // MEDIA_RECOMMENDATION + else + 31, // MEDIA_RESUME + uid, + interactedSubcardRank, + interactedSubcardCardinality + ) /* ktlint-disable max-line-length */ } @@ -738,18 +785,20 @@ class MediaCarouselController @Inject constructor( if (!recommendation.isEmpty()) { logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS recommendation.get(0).mInstanceId, + recommendation.get(0).mUid, true, recommendation.get(0).surfaceForSmartspaceLogging, - /* rank */-1) + rank = -1) } else { val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex if (MediaPlayerData.players().size > visibleMediaIndex) { val player = MediaPlayerData.players().elementAt(visibleMediaIndex) logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS player.mInstanceId, - false, + player.mUid, + false, player.surfaceForSmartspaceLogging, - /* rank */-1) + rank = -1) } } mediaManager.onSwipeToDismiss() @@ -768,7 +817,7 @@ class MediaCarouselController @Inject constructor( @VisibleForTesting internal object MediaPlayerData { private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null, - emptyList(), emptyList(), "INVALID", null, null, null, true, null) + emptyList(), emptyList(), "INVALID", null, null, null, true, null) // Whether should prioritize Smartspace card. internal var shouldPrioritizeSs: Boolean = false private set @@ -776,18 +825,18 @@ internal object MediaPlayerData { private set data class MediaSortKey( - // Whether the item represents a Smartspace media recommendation. + // Whether the item represents a Smartspace media recommendation. val isSsMediaRec: Boolean, val data: MediaData, val updateTime: Long = 0 ) private val comparator = - compareByDescending<MediaSortKey> { it.data.isPlaying } - .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec } - .thenByDescending { it.data.isLocalSession } - .thenByDescending { !it.data.resumption } - .thenByDescending { it.updateTime } + compareByDescending<MediaSortKey> { it.data.isPlaying } + .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec } + .thenByDescending { it.data.isLocalSession } + .thenByDescending { !it.data.resumption } + .thenByDescending { it.updateTime } private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator) private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf() @@ -888,4 +937,4 @@ internal object MediaPlayerData { } return false } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 15a70831b2f9..c125612380d3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -33,6 +33,7 @@ import android.graphics.drawable.Icon; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; +import android.os.Process; import android.text.Layout; import android.util.Log; import android.view.View; @@ -111,6 +112,9 @@ public class MediaControlPanel { private int mAlbumArtSize; // Instance id for logging purpose. protected int mInstanceId = -1; + // Uid for the media app. + protected int mUid = Process.INVALID_UID; + private int mSmartspaceMediaItemsCount; private MediaCarouselController mMediaCarouselController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; @@ -266,7 +270,13 @@ public class MediaControlPanel { } mKey = key; MediaSession.Token token = data.getToken(); - mInstanceId = SmallHash.hash(data.getPackageName()); + PackageManager packageManager = mContext.getPackageManager(); + try { + mUid = packageManager.getApplicationInfo(data.getPackageName(), 0 /* flags */).uid; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Unable to look up package name", e); + } + mInstanceId = SmallHash.hash(mUid); mBackgroundColor = data.getBackgroundColor(); if (mToken == null || !mToken.equals(token)) { @@ -360,27 +370,16 @@ public class MediaControlPanel { final MediaDeviceData device = data.getDevice(); final int seamlessId = mPlayerViewHolder.getSeamless().getId(); - final int seamlessFallbackId = mPlayerViewHolder.getSeamlessFallback().getId(); - final boolean showFallback = device != null && !device.getEnabled(); - final int seamlessFallbackVisibility = showFallback ? View.VISIBLE : View.GONE; - mPlayerViewHolder.getSeamlessFallback().setVisibility(seamlessFallbackVisibility); - expandedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility); - collapsedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility); - final int seamlessVisibility = showFallback ? View.GONE : View.VISIBLE; - mPlayerViewHolder.getSeamless().setVisibility(seamlessVisibility); - expandedSet.setVisibility(seamlessId, seamlessVisibility); - collapsedSet.setVisibility(seamlessId, seamlessVisibility); - final float seamlessAlpha = data.getResumption() ? DISABLED_ALPHA : 1.0f; + // Disable clicking on output switcher for invalid devices and resumption controls + final boolean seamlessDisabled = (device != null && !device.getEnabled()) + || data.getResumption(); + final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f; expandedSet.setAlpha(seamlessId, seamlessAlpha); collapsedSet.setAlpha(seamlessId, seamlessAlpha); - // Disable clicking on output switcher for resumption controls. - mPlayerViewHolder.getSeamless().setEnabled(!data.getResumption()); + mPlayerViewHolder.getSeamless().setEnabled(!seamlessDisabled); String deviceString = null; - if (showFallback) { - iconView.setImageDrawable(null); - } else if (device != null) { + if (device != null && device.getEnabled()) { Drawable icon = device.getIcon(); - iconView.setVisibility(View.VISIBLE); if (icon instanceof AdaptiveIcon) { AdaptiveIcon aIcon = (AdaptiveIcon) icon; aIcon.setBackgroundColor(mBackgroundColor); @@ -391,10 +390,9 @@ public class MediaControlPanel { deviceString = device.getName(); } else { // Reset to default - Log.w(TAG, "device is null. Not binding output chip."); - iconView.setVisibility(View.GONE); - deviceString = mContext.getString( - com.android.internal.R.string.ext_media_seamless_action); + Log.w(TAG, "Device is null or not enabled: " + device + ", not binding output chip."); + iconView.setImageResource(R.drawable.ic_media_home_devices); + deviceString = mContext.getString(R.string.media_seamless_other_device); } deviceName.setText(deviceString); seamlessView.setContentDescription(deviceString); @@ -531,10 +529,11 @@ public class MediaControlPanel { } // Set up recommendation card's header. - ApplicationInfo applicationInfo = null; + ApplicationInfo applicationInfo; try { applicationInfo = mContext.getPackageManager() .getApplicationInfo(data.getPackageName(), 0 /* flags */); + mUid = applicationInfo.uid; } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Fail to get media recommendation's app info", e); return; @@ -553,7 +552,8 @@ public class MediaControlPanel { headerTitleText.setText(appLabel); } // Set up media rec card's tap action if applicable. - setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction()); + setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(), + /* interactedSubcardRank */ -1); // Set up media rec card's accessibility label. recommendationCard.setContentDescription( mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel)); @@ -567,7 +567,8 @@ public class MediaControlPanel { ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); int mediaRecommendationNum = Math.min(mediaRecommendationList.size(), MEDIA_RECOMMENDATION_MAX_NUM); - for (int itemIndex = 0, uiComponentIndex = 0; + int uiComponentIndex = 0; + for (int itemIndex = 0; itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum; itemIndex++) { SmartspaceAction recommendation = mediaRecommendationList.get(itemIndex); @@ -582,7 +583,8 @@ public class MediaControlPanel { // Set up the media item's click listener if applicable. ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex); - setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation); + setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation, + uiComponentIndex); // Set up the accessibility label for the media item. String artistName = recommendation.getExtras() @@ -614,10 +616,10 @@ public class MediaControlPanel { mediaCoverItemsResIds.get(uiComponentIndex), true); setVisibleAndAlpha(expandedSet, mediaCoverContainersResIds.get(uiComponentIndex), true); - uiComponentIndex++; } + mSmartspaceMediaItemsCount = uiComponentIndex; // Set up long press to show guts setting panel. mRecommendationViewHolder.getDismiss().setOnClickListener(v -> { logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS @@ -750,7 +752,8 @@ public class MediaControlPanel { private void setSmartspaceRecItemOnClickListener( @NonNull View view, - @NonNull SmartspaceAction action) { + @NonNull SmartspaceAction action, + int interactedSubcardRank) { if (view == null || action == null || action.getIntent() == null || action.getIntent().getExtras() == null) { Log.e(TAG, "No tap action can be set up"); @@ -758,9 +761,10 @@ public class MediaControlPanel { } view.setOnClickListener(v -> { - // When media recommendation card is shown, it will always be the top card. logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK - /* isRecommendationCard */ true); + /* isRecommendationCard */ true, + interactedSubcardRank, + getSmartspaceSubCardCardinality()); if (shouldSmartspaceRecItemOpenInForeground(action)) { // Request to unlock the device if the activity needs to be opened in foreground. @@ -818,9 +822,28 @@ public class MediaControlPanel { } private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard) { + logSmartspaceCardReported(eventId, isRecommendationCard, + /* interactedSubcardRank */ 0, + /* interactedSubcardCardinality */ 0); + } + + private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard, + int interactedSubcardRank, int interactedSubcardCardinality) { mMediaCarouselController.logSmartspaceCardReported(eventId, mInstanceId, + mUid, isRecommendationCard, - getSurfaceForSmartspaceLogging()); + getSurfaceForSmartspaceLogging(), + interactedSubcardRank, + interactedSubcardCardinality); + } + + private int getSmartspaceSubCardCardinality() { + if (!mMediaCarouselController.getMediaCarouselScrollHandler().getQsExpanded() + && mSmartspaceMediaItemsCount > 3) { + return 3; + } + + return mSmartspaceMediaItemsCount; } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 0a28b47923da..ba99f5df653c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -212,8 +212,8 @@ class MediaDataManager( mediaDataCombineLatest.addListener(mediaDataFilter) // Set up links back into the pipeline for listeners that need to send events upstream. - mediaTimeoutListener.timeoutCallback = { token: String, timedOut: Boolean -> - setTimedOut(token, timedOut) } + mediaTimeoutListener.timeoutCallback = { key: String, timedOut: Boolean -> + setTimedOut(key, timedOut) } mediaResumeListener.setManager(this) mediaDataFilter.mediaDataManager = this @@ -414,14 +414,18 @@ class MediaDataManager( * This will make the player not active anymore, hiding it from QQS and Keyguard. * @see MediaData.active */ - internal fun setTimedOut(token: String, timedOut: Boolean, forceUpdate: Boolean = false) { - mediaEntries[token]?.let { + internal fun setTimedOut(key: String, timedOut: Boolean, forceUpdate: Boolean = false) { + mediaEntries[key]?.let { if (it.active == !timedOut && !forceUpdate) { + if (it.resumption) { + if (DEBUG) Log.d(TAG, "timing out resume player $key") + dismissMediaData(key, 0L /* delay */) + } return } it.active = !timedOut - if (DEBUG) Log.d(TAG, "Updating $token timedOut: $timedOut") - onMediaDataLoaded(token, token, it) + if (DEBUG) Log.d(TAG, "Updating $key timedOut: $timedOut") + onMediaDataLoaded(key, key, it) } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt index ab568c8c5a85..608c784f5d39 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt @@ -35,6 +35,7 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dump.DumpManager import com.android.systemui.tuner.TunerService import com.android.systemui.util.Utils +import com.android.systemui.util.time.SystemClock import java.io.FileDescriptor import java.io.PrintWriter import java.util.concurrent.ConcurrentLinkedQueue @@ -53,11 +54,13 @@ class MediaResumeListener @Inject constructor( @Background private val backgroundExecutor: Executor, private val tunerService: TunerService, private val mediaBrowserFactory: ResumeMediaBrowserFactory, - dumpManager: DumpManager + dumpManager: DumpManager, + private val systemClock: SystemClock ) : MediaDataManager.Listener, Dumpable { private var useMediaResumption: Boolean = Utils.useMediaResumption(context) - private val resumeComponents: ConcurrentLinkedQueue<ComponentName> = ConcurrentLinkedQueue() + private val resumeComponents: ConcurrentLinkedQueue<Pair<ComponentName, Long>> = + ConcurrentLinkedQueue() private lateinit var mediaDataManager: MediaDataManager @@ -131,14 +134,32 @@ class MediaResumeListener @Inject constructor( val listString = prefs.getString(MEDIA_PREFERENCE_KEY + currentUserId, null) val components = listString?.split(ResumeMediaBrowser.DELIMITER.toRegex()) ?.dropLastWhile { it.isEmpty() } + var needsUpdate = false components?.forEach { val info = it.split("/") val packageName = info[0] val className = info[1] val component = ComponentName(packageName, className) - resumeComponents.add(component) + + val lastPlayed = if (info.size == 3) { + try { + info[2].toLong() + } catch (e: NumberFormatException) { + needsUpdate = true + systemClock.currentTimeMillis() + } + } else { + needsUpdate = true + systemClock.currentTimeMillis() + } + resumeComponents.add(component to lastPlayed) } Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}") + + if (needsUpdate) { + // Save any missing times that we had to fill in + writeSharedPrefs() + } } /** @@ -149,9 +170,12 @@ class MediaResumeListener @Inject constructor( return } + val now = systemClock.currentTimeMillis() resumeComponents.forEach { - val browser = mediaBrowserFactory.create(mediaBrowserCallback, it) - browser.findRecentMedia() + if (now.minus(it.second) <= RESUME_MEDIA_TIMEOUT) { + val browser = mediaBrowserFactory.create(mediaBrowserCallback, it.first) + browser.findRecentMedia() + } } } @@ -234,18 +258,24 @@ class MediaResumeListener @Inject constructor( */ private fun updateResumptionList(componentName: ComponentName) { // Remove if exists - resumeComponents.remove(componentName) + resumeComponents.remove(resumeComponents.find { it.first.equals(componentName) }) // Insert at front of queue - resumeComponents.add(componentName) + val currentTime = systemClock.currentTimeMillis() + resumeComponents.add(componentName to currentTime) // Remove old components if over the limit if (resumeComponents.size > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) { resumeComponents.remove() } - // Save changes + writeSharedPrefs() + } + + private fun writeSharedPrefs() { val sb = StringBuilder() resumeComponents.forEach { - sb.append(it.flattenToString()) + sb.append(it.first.flattenToString()) + sb.append("/") + sb.append(it.second) sb.append(ResumeMediaBrowser.DELIMITER) } val prefs = context.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE) diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt index 9a3919326cbd..6f047712c954 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt @@ -20,6 +20,7 @@ import android.media.session.MediaController import android.media.session.PlaybackState import android.os.SystemProperties import android.util.Log +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState @@ -29,9 +30,15 @@ import javax.inject.Inject private const val DEBUG = true private const val TAG = "MediaTimeout" -private val PAUSED_MEDIA_TIMEOUT = SystemProperties + +@VisibleForTesting +val PAUSED_MEDIA_TIMEOUT = SystemProperties .getLong("debug.sysui.media_timeout", TimeUnit.MINUTES.toMillis(10)) +@VisibleForTesting +val RESUME_MEDIA_TIMEOUT = SystemProperties + .getLong("debug.sysui.media_timeout_resume", TimeUnit.DAYS.toMillis(3)) + /** * Controller responsible for keeping track of playback states and expiring inactive streams. */ @@ -45,8 +52,9 @@ class MediaTimeoutListener @Inject constructor( /** * Callback representing that a media object is now expired: - * @param token Media session unique identifier - * @param pauseTimeout True when expired for {@code PAUSED_MEDIA_TIMEOUT} + * @param key Media control unique identifier + * @param timedOut True when expired for {@code PAUSED_MEDIA_TIMEOUT} for active media, + * or {@code RESUME_MEDIA_TIMEOUT} for resume media */ lateinit var timeoutCallback: (String, Boolean) -> Unit @@ -122,6 +130,7 @@ class MediaTimeoutListener @Inject constructor( var timedOut = false var playing: Boolean? = null + var resumption: Boolean? = null var destroyed = false var mediaData: MediaData = data @@ -159,12 +168,19 @@ class MediaTimeoutListener @Inject constructor( } override fun onSessionDestroyed() { - // If the session is destroyed, the controller is no longer valid, and we will need to - // recreate it if this key is updated later if (DEBUG) { Log.d(TAG, "Session destroyed for $key") } - destroy() + + if (resumption == true) { + // Some apps create a session when MBS is queried. We should unregister the + // controller since it will no longer be valid, but don't cancel the timeout + mediaController?.unregisterCallback(this) + } else { + // For active controls, if the session is destroyed, clean up everything since we + // will need to recreate it if this key is updated later + destroy() + } } private fun processState(state: PlaybackState?, dispatchEvents: Boolean) { @@ -173,20 +189,28 @@ class MediaTimeoutListener @Inject constructor( } val isPlaying = state != null && isPlayingState(state.state) - if (playing == isPlaying && playing != null) { + val resumptionChanged = resumption != mediaData.resumption + if (playing == isPlaying && playing != null && !resumptionChanged) { return } playing = isPlaying + resumption = mediaData.resumption if (!isPlaying) { if (DEBUG) { - Log.v(TAG, "schedule timeout for $key") + Log.v(TAG, "schedule timeout for $key playing $isPlaying, $resumption") } - if (cancellation != null) { + if (cancellation != null && !resumptionChanged) { + // if the media changed resume state, we'll need to adjust the timeout length if (DEBUG) Log.d(TAG, "cancellation already exists, continuing.") return } - expireMediaTimeout(key, "PLAYBACK STATE CHANGED - $state") + expireMediaTimeout(key, "PLAYBACK STATE CHANGED - $state, $resumption") + val timeout = if (mediaData.resumption) { + RESUME_MEDIA_TIMEOUT + } else { + PAUSED_MEDIA_TIMEOUT + } cancellation = mainExecutor.executeDelayed({ cancellation = null if (DEBUG) { @@ -195,7 +219,7 @@ class MediaTimeoutListener @Inject constructor( timedOut = true // this event is async, so it's safe even when `dispatchEvents` is false timeoutCallback(key, timedOut) - }, PAUSED_MEDIA_TIMEOUT) + }, timeout) } else { expireMediaTimeout(key, "playback started - $state, $key") timedOut = false diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt index 791f59d3ae13..35603b6ef6cc 100644 --- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt @@ -43,7 +43,6 @@ class PlayerViewHolder private constructor(itemView: View) { val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless) val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image) val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text) - val seamlessFallback = itemView.requireViewById<ImageView>(R.id.media_seamless_fallback) // Seek bar val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar) @@ -124,7 +123,6 @@ class PlayerViewHolder private constructor(itemView: View) { R.id.header_title, R.id.header_artist, R.id.media_seamless, - R.id.media_seamless_fallback, R.id.notification_media_progress_time, R.id.media_progress_bar, R.id.action0, diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java deleted file mode 100644 index 38b20ee45946..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui.qs; - -import static com.android.systemui.statusbar.phone.AutoTileManager.HOTSPOT; -import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION; -import static com.android.systemui.statusbar.phone.AutoTileManager.NIGHT; -import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER; -import static com.android.systemui.statusbar.phone.AutoTileManager.WORK; - -import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings.Secure; -import android.text.TextUtils; -import android.util.ArraySet; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Prefs; -import com.android.systemui.Prefs.Key; -import com.android.systemui.util.UserAwareController; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import javax.inject.Inject; - -public class AutoAddTracker implements UserAwareController { - - private static final String[][] CONVERT_PREFS = { - {Key.QS_HOTSPOT_ADDED, HOTSPOT}, - {Key.QS_DATA_SAVER_ADDED, SAVER}, - {Key.QS_INVERT_COLORS_ADDED, INVERSION}, - {Key.QS_WORK_ADDED, WORK}, - {Key.QS_NIGHTDISPLAY_ADDED, NIGHT}, - }; - - private final ArraySet<String> mAutoAdded; - private final Context mContext; - private int mUserId; - - public AutoAddTracker(Context context, int userId) { - mContext = context; - mUserId = userId; - mAutoAdded = new ArraySet<>(getAdded()); - } - - /** - * Init method must be called after construction to start listening - */ - public void initialize() { - // TODO: remove migration code and shared preferences keys after P release - if (mUserId == UserHandle.USER_SYSTEM) { - for (String[] convertPref : CONVERT_PREFS) { - if (Prefs.getBoolean(mContext, convertPref[0], false)) { - setTileAdded(convertPref[1]); - Prefs.remove(mContext, convertPref[0]); - } - } - } - mContext.getContentResolver().registerContentObserver( - Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver, - UserHandle.USER_ALL); - } - - @Override - public void changeUser(UserHandle newUser) { - if (newUser.getIdentifier() == mUserId) { - return; - } - mUserId = newUser.getIdentifier(); - mAutoAdded.clear(); - mAutoAdded.addAll(getAdded()); - } - - @Override - public int getCurrentUserId() { - return mUserId; - } - - public boolean isAdded(String tile) { - return mAutoAdded.contains(tile); - } - - public void setTileAdded(String tile) { - if (mAutoAdded.add(tile)) { - saveTiles(); - } - } - - public void setTileRemoved(String tile) { - if (mAutoAdded.remove(tile)) { - saveTiles(); - } - } - - public void destroy() { - mContext.getContentResolver().unregisterContentObserver(mObserver); - } - - private void saveTiles() { - Secure.putStringForUser(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, - TextUtils.join(",", mAutoAdded), mUserId); - } - - private Collection<String> getAdded() { - String current = Secure.getStringForUser(mContext.getContentResolver(), - Secure.QS_AUTO_ADDED_TILES, mUserId); - if (current == null) { - return Collections.emptyList(); - } - return Arrays.asList(current.split(",")); - } - - @VisibleForTesting - protected final ContentObserver mObserver = new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - mAutoAdded.clear(); - mAutoAdded.addAll(getAdded()); - } - }; - - public static class Builder { - private final Context mContext; - private int mUserId; - - @Inject - public Builder(Context context) { - mContext = context; - } - - public Builder setUserId(int userId) { - mUserId = userId; - return this; - } - - public AutoAddTracker build() { - return new AutoAddTracker(mContext, mUserId); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt new file mode 100644 index 000000000000..7ffa9d931ff0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.database.ContentObserver +import android.net.Uri +import android.os.Handler +import android.os.UserHandle +import android.provider.Settings +import android.text.TextUtils +import android.util.ArraySet +import android.util.Log +import androidx.annotation.GuardedBy +import androidx.annotation.VisibleForTesting +import com.android.systemui.Dumpable +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dump.DumpManager +import com.android.systemui.util.UserAwareController +import com.android.systemui.util.settings.SecureSettings +import java.io.FileDescriptor +import java.io.PrintWriter +import java.util.concurrent.Executor +import javax.inject.Inject + +private const val TAG = "AutoAddTracker" + +/** + * Class to track tiles that have been auto-added + * + * The list is backed by [Settings.Secure.QS_AUTO_ADDED_TILES]. + * + * It also handles restore gracefully. + */ +class AutoAddTracker @VisibleForTesting constructor( + private val secureSettings: SecureSettings, + private val broadcastDispatcher: BroadcastDispatcher, + private val qsHost: QSHost, + private val dumpManager: DumpManager, + private val mainHandler: Handler?, + private val backgroundExecutor: Executor, + private var userId: Int +) : UserAwareController, Dumpable { + + companion object { + private val FILTER = IntentFilter(Intent.ACTION_SETTING_RESTORED) + } + + @GuardedBy("autoAdded") + private val autoAdded = ArraySet<String>() + private var restoredTiles: Set<String>? = null + + override val currentUserId: Int + get() = userId + + private val contentObserver = object : ContentObserver(mainHandler) { + override fun onChange( + selfChange: Boolean, + uris: Collection<Uri>, + flags: Int, + _userId: Int + ) { + if (_userId != userId) { + // Ignore changes outside of our user. We'll load the correct value on user change + return + } + loadTiles() + } + } + + private val restoreReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action != Intent.ACTION_SETTING_RESTORED) return + processRestoreIntent(intent) + } + } + + private fun processRestoreIntent(intent: Intent) { + when (intent.getStringExtra(Intent.EXTRA_SETTING_NAME)) { + Settings.Secure.QS_TILES -> { + restoredTiles = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE) + ?.split(",") + ?.toSet() + ?: run { + Log.w(TAG, "Null restored tiles for user $userId") + emptySet() + } + } + Settings.Secure.QS_AUTO_ADDED_TILES -> { + restoredTiles?.let { tiles -> + val restoredAutoAdded = intent + .getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE) + ?.split(",") + ?: emptyList() + val autoAddedBeforeRestore = intent + .getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE) + ?.split(",") + ?: emptyList() + + val tilesToRemove = restoredAutoAdded.filter { it !in tiles } + if (tilesToRemove.isNotEmpty()) { + qsHost.removeTiles(tilesToRemove) + } + val tiles = synchronized(autoAdded) { + autoAdded.clear() + autoAdded.addAll(restoredAutoAdded + autoAddedBeforeRestore) + getTilesFromListLocked() + } + saveTiles(tiles) + } ?: run { + Log.w(TAG, "${Settings.Secure.QS_AUTO_ADDED_TILES} restored before " + + "${Settings.Secure.QS_TILES} for user $userId") + } + } + else -> {} // Do nothing for other Settings + } + } + + /** + * Init method must be called after construction to start listening + */ + fun initialize() { + dumpManager.registerDumpable(TAG, this) + loadTiles() + secureSettings.registerContentObserverForUser( + secureSettings.getUriFor(Settings.Secure.QS_AUTO_ADDED_TILES), + contentObserver, + UserHandle.USER_ALL + ) + registerBroadcastReceiver() + } + + /** + * Unregister listeners, receivers and observers + */ + fun destroy() { + dumpManager.unregisterDumpable(TAG) + secureSettings.unregisterContentObserver(contentObserver) + unregisterBroadcastReceiver() + } + + private fun registerBroadcastReceiver() { + broadcastDispatcher.registerReceiver( + restoreReceiver, + FILTER, + backgroundExecutor, + UserHandle.of(userId) + ) + } + + private fun unregisterBroadcastReceiver() { + broadcastDispatcher.unregisterReceiver(restoreReceiver) + } + + override fun changeUser(newUser: UserHandle) { + if (newUser.identifier == userId) return + unregisterBroadcastReceiver() + userId = newUser.identifier + restoredTiles = null + loadTiles() + registerBroadcastReceiver() + } + + /** + * Returns `true` if the tile has been auto-added before + */ + fun isAdded(tile: String): Boolean { + return synchronized(autoAdded) { + tile in autoAdded + } + } + + /** + * Sets a tile as auto-added. + * + * From here on, [isAdded] will return true for that tile. + */ + fun setTileAdded(tile: String) { + val tiles = synchronized(autoAdded) { + if (autoAdded.add(tile)) { + getTilesFromListLocked() + } else { + null + } + } + tiles?.let { saveTiles(it) } + } + + /** + * Removes a tile from the list of auto-added. + * + * This allows for this tile to be auto-added again in the future. + */ + fun setTileRemoved(tile: String) { + val tiles = synchronized(autoAdded) { + if (autoAdded.remove(tile)) { + getTilesFromListLocked() + } else { + null + } + } + tiles?.let { saveTiles(it) } + } + + private fun getTilesFromListLocked(): String { + return TextUtils.join(",", autoAdded) + } + + private fun saveTiles(tiles: String) { + secureSettings.putStringForUser( + Settings.Secure.QS_AUTO_ADDED_TILES, + tiles, + /* tag */ null, + /* makeDefault */ false, + userId, + /* overrideableByRestore */ true + ) + } + + private fun loadTiles() { + synchronized(autoAdded) { + autoAdded.clear() + autoAdded.addAll(getAdded()) + } + } + + private fun getAdded(): Collection<String> { + val current = secureSettings.getStringForUser(Settings.Secure.QS_AUTO_ADDED_TILES, userId) + return current?.split(",") ?: emptySet() + } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("Current user: $userId") + pw.println("Added tiles: $autoAdded") + } + + @SysUISingleton + class Builder @Inject constructor( + private val secureSettings: SecureSettings, + private val broadcastDispatcher: BroadcastDispatcher, + private val qsHost: QSHost, + private val dumpManager: DumpManager, + @Main private val handler: Handler, + @Background private val executor: Executor + ) { + private var userId: Int = 0 + + fun setUserId(_userId: Int): Builder { + userId = _userId + return this + } + + fun build(): AutoAddTracker { + return AutoAddTracker( + secureSettings, + broadcastDispatcher, + qsHost, + dumpManager, + handler, + executor, + userId + ) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index 000fd1c4bd2e..9f585bdfaeb0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -37,6 +37,7 @@ public interface QSHost { void removeCallback(Callback callback); TileServices getTileServices(); void removeTile(String tileSpec); + void removeTiles(Collection<String> specs); void unmarkTileAsAutoAdded(String tileSpec); int indexOf(String tileSpec); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 4a75810f86db..d5349d378305 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -51,7 +51,6 @@ import com.android.systemui.qs.external.TileServices; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -96,7 +95,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final UiEventLogger mUiEventLogger; private final InstanceIdSequence mInstanceIdSequence; private final CustomTileStatePersister mCustomTileStatePersister; - private final FeatureFlags mFeatureFlags; private final List<Callback> mCallbacks = new ArrayList<>(); private AutoTileManager mAutoTiles; @@ -124,8 +122,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D UiEventLogger uiEventLogger, UserTracker userTracker, SecureSettings secureSettings, - CustomTileStatePersister customTileStatePersister, - FeatureFlags featureFlags + CustomTileStatePersister customTileStatePersister ) { mIconController = iconController; mContext = context; @@ -147,7 +144,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mUserTracker = userTracker; mSecureSettings = secureSettings; mCustomTileStatePersister = customTileStatePersister; - mFeatureFlags = featureFlags; mainHandler.post(() -> { // This is technically a hack to avoid circular dependency of @@ -269,7 +265,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) { newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode); } - final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags); + final List<String> tileSpecs = loadTileSpecs(mContext, newValue); int currentUser = mUserTracker.getUserId(); if (currentUser != mCurrentUser) { mUserContext = mUserTracker.getUserContext(); @@ -338,7 +334,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newTiles.isEmpty() && !tileSpecs.isEmpty()) { // If we didn't manage to create any tiles, set it to empty (default) Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); - changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags)); + changeTiles(currentSpecs, loadTileSpecs(mContext, "")); } else { for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onTilesChanged(); @@ -351,6 +347,17 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D changeTileSpecs(tileSpecs-> tileSpecs.remove(spec)); } + /** + * Remove many tiles at once. + * + * It will only save to settings once (as opposed to {@link QSTileHost#removeTile} called + * multiple times). + */ + @Override + public void removeTiles(Collection<String> specs) { + changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs)); + } + @Override public void unmarkTileAsAutoAdded(String spec) { if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec); @@ -372,6 +379,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D * @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X */ public void addTile(String spec, int requestPosition) { + if (spec.equals("work")) Log.wtfStack(TAG, "Adding work tile"); changeTileSpecs(tileSpecs -> { if (tileSpecs.contains(spec)) return false; @@ -386,6 +394,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } void saveTilesToSettings(List<String> tileSpecs) { + if (tileSpecs.contains("work")) Log.wtfStack(TAG, "Saving work tile"); mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs), null /* tag */, false /* default */, mCurrentUser, true /* overrideable by restore */); @@ -393,7 +402,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private void changeTileSpecs(Predicate<List<String>> changeFunction) { final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser); - final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags); + final List<String> tileSpecs = loadTileSpecs(mContext, setting); if (changeFunction.test(tileSpecs)) { saveTilesToSettings(tileSpecs); } @@ -482,8 +491,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec()); } - protected static List<String> loadTileSpecs( - Context context, String tileList, FeatureFlags featureFlags) { + protected static List<String> loadTileSpecs(Context context, String tileList) { final Resources res = context.getResources(); if (TextUtils.isEmpty(tileList)) { @@ -516,21 +524,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } } } - if (featureFlags.isProviderModelSettingEnabled()) { - if (!tiles.contains("internet")) { - if (tiles.contains("wifi")) { - // Replace the WiFi with Internet, and remove the Cell - tiles.set(tiles.indexOf("wifi"), "internet"); - tiles.remove("cell"); - } else if (tiles.contains("cell")) { - // Replace the Cell with Internet - tiles.set(tiles.indexOf("cell"), "internet"); - } - } else { - tiles.remove("wifi"); - tiles.remove("cell"); - } - } return tiles; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 77906abce625..5838b8f7a34c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconMa import com.android.systemui.statusbar.phone.StatusBarWindowView; import com.android.systemui.statusbar.phone.StatusIconContainer; import com.android.systemui.statusbar.policy.Clock; +import com.android.systemui.statusbar.policy.VariableDateView; import java.util.List; @@ -62,11 +63,14 @@ public class QuickStatusBarHeader extends FrameLayout { protected QuickQSPanel mHeaderQsPanel; private View mDatePrivacyView; private View mDateView; + // DateView next to clock. Visible on QQS + private VariableDateView mClockDateView; private View mSecurityHeaderView; private View mClockIconsView; private View mContainer; private View mQSCarriers; + private ViewGroup mClockContainer; private Clock mClockView; private Space mDatePrivacySeparator; private View mClockIconsSeparator; @@ -86,7 +90,6 @@ public class QuickStatusBarHeader extends FrameLayout { private int mWaterfallTopInset; private int mCutOutPaddingLeft; private int mCutOutPaddingRight; - private float mViewAlpha = 1.0f; private float mKeyguardExpansionFraction; private int mTextColorPrimary = Color.TRANSPARENT; private int mTopViewMeasureHeight; @@ -123,18 +126,24 @@ public class QuickStatusBarHeader extends FrameLayout { mIconContainer = findViewById(R.id.statusIcons); mPrivacyChip = findViewById(R.id.privacy_chip); mDateView = findViewById(R.id.date); + mClockDateView = findViewById(R.id.date_clock); mSecurityHeaderView = findViewById(R.id.header_text_container); mClockIconsSeparator = findViewById(R.id.separator); mRightLayout = findViewById(R.id.rightLayout); mDateContainer = findViewById(R.id.date_container); mPrivacyContainer = findViewById(R.id.privacy_container); + mClockContainer = findViewById(R.id.clock_container); mClockView = findViewById(R.id.clock); mDatePrivacySeparator = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon); updateResources(); + Configuration config = mContext.getResources().getConfiguration(); + setDatePrivacyContainersWidth(config.orientation == Configuration.ORIENTATION_LANDSCAPE); + setSecurityHeaderContainerVisibility( + config.orientation == Configuration.ORIENTATION_LANDSCAPE); // Don't need to worry about tuner settings for this icon mBatteryRemainingIcon.setIgnoreTunerUpdates(true); @@ -177,7 +186,7 @@ public class QuickStatusBarHeader extends FrameLayout { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mDatePrivacyView.getMeasuredHeight() != mTopViewMeasureHeight) { mTopViewMeasureHeight = mDatePrivacyView.getMeasuredHeight(); - updateAnimators(); + post(this::updateAnimators); } } @@ -186,6 +195,8 @@ public class QuickStatusBarHeader extends FrameLayout { super.onConfigurationChanged(newConfig); updateResources(); setDatePrivacyContainersWidth(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); + setSecurityHeaderContainerVisibility( + newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); } @Override @@ -206,6 +217,10 @@ public class QuickStatusBarHeader extends FrameLayout { mPrivacyContainer.setLayoutParams(lp); } + private void setSecurityHeaderContainerVisibility(boolean landscape) { + mSecurityHeaderView.setVisibility(landscape ? VISIBLE : GONE); + } + private void updateBatteryMode() { if (mConfigShowBatteryEstimate && !mHasCenterCutout) { mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); @@ -280,7 +295,8 @@ public class QuickStatusBarHeader extends FrameLayout { TouchAnimator.Builder builder = new TouchAnimator.Builder() .addFloat(mSecurityHeaderView, "alpha", 0, 1) // These views appear on expanding down - .addFloat(mClockView, "alpha", 0, 1) + .addFloat(mDateView, "alpha", 0, 0, 1) + .addFloat(mClockDateView, "alpha", 1, 0, 0) .addFloat(mQSCarriers, "alpha", 0, 1) .setListener(new TouchAnimator.ListenerAdapter() { @Override @@ -289,10 +305,14 @@ public class QuickStatusBarHeader extends FrameLayout { if (!mIsSingleCarrier) { mIconContainer.addIgnoredSlots(mRssiIgnoredSlots); } + // Make it gone so there's enough room for carrier names + mClockDateView.setVisibility(View.GONE); } @Override public void onAnimationStarted() { + mClockDateView.setVisibility(View.VISIBLE); + mClockDateView.setFreezeSwitching(true); setSeparatorVisibility(false); if (!mIsSingleCarrier) { mIconContainer.addIgnoredSlots(mRssiIgnoredSlots); @@ -302,6 +322,8 @@ public class QuickStatusBarHeader extends FrameLayout { @Override public void onAnimationAtStart() { super.onAnimationAtStart(); + mClockDateView.setFreezeSwitching(false); + mClockDateView.setVisibility(View.VISIBLE); setSeparatorVisibility(mShowClockIconsSeparator); // In QQS we never ignore RSSI. mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots); @@ -434,10 +456,11 @@ public class QuickStatusBarHeader extends FrameLayout { mClockIconsSeparator.setVisibility(visible ? View.VISIBLE : View.GONE); mQSCarriers.setVisibility(visible ? View.GONE : View.VISIBLE); - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mClockView.getLayoutParams(); + LinearLayout.LayoutParams lp = + (LinearLayout.LayoutParams) mClockContainer.getLayoutParams(); lp.width = visible ? 0 : WRAP_CONTENT; lp.weight = visible ? 1f : 0f; - mClockView.setLayoutParams(lp); + mClockContainer.setLayoutParams(lp); lp = (LinearLayout.LayoutParams) mRightLayout.getLayoutParams(); lp.width = visible ? 0 : WRAP_CONTENT; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index da75c9e45c54..18d6e646b007 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -41,6 +41,7 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusIconContainer; import com.android.systemui.statusbar.policy.Clock; +import com.android.systemui.statusbar.policy.VariableDateViewController; import com.android.systemui.util.ViewController; import java.util.List; @@ -71,6 +72,9 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader private final QSExpansionPathInterpolator mQSExpansionPathInterpolator; private final FeatureFlags mFeatureFlags; + private final VariableDateViewController mVariableDateViewControllerDateView; + private final VariableDateViewController mVariableDateViewControllerClockDateView; + private boolean mListening; private boolean mMicCameraIndicatorsEnabled; private boolean mLocationIndicatorsEnabled; @@ -134,7 +138,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader SysuiColorExtractor colorExtractor, PrivacyDialogController privacyDialogController, QSExpansionPathInterpolator qsExpansionPathInterpolator, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + VariableDateViewController.Factory variableDateViewControllerFactory) { super(view); mPrivacyItemController = privacyItemController; mActivityStarter = activityStarter; @@ -154,6 +159,12 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mPrivacyChip = mView.findViewById(R.id.privacy_chip); mClockView = mView.findViewById(R.id.clock); mIconContainer = mView.findViewById(R.id.statusIcons); + mVariableDateViewControllerDateView = variableDateViewControllerFactory.create( + mView.requireViewById(R.id.date) + ); + mVariableDateViewControllerClockDateView = variableDateViewControllerFactory.create( + mView.requireViewById(R.id.date_clock) + ); mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags); mDemoModeReceiver = new ClockDemoModeReceiver(mClockView); @@ -205,6 +216,9 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots); mDemoModeController.addCallback(mDemoModeReceiver); + + mVariableDateViewControllerDateView.init(); + mVariableDateViewControllerClockDateView.init(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index f2832b3d45ff..3c2f35b954ea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -41,7 +41,6 @@ import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon; import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.leak.GarbageMonitor; import java.util.ArrayList; @@ -63,7 +62,6 @@ public class TileQueryHelper { private final Executor mBgExecutor; private final Context mContext; private final UserTracker mUserTracker; - private final FeatureFlags mFeatureFlags; private TileStateListener mListener; private boolean mFinished; @@ -73,14 +71,12 @@ public class TileQueryHelper { Context context, UserTracker userTracker, @Main Executor mainExecutor, - @Background Executor bgExecutor, - FeatureFlags featureFlags + @Background Executor bgExecutor ) { mContext = context; mMainExecutor = mainExecutor; mBgExecutor = bgExecutor; mUserTracker = userTracker; - mFeatureFlags = featureFlags; } public void setListener(TileStateListener listener) { @@ -121,10 +117,6 @@ public class TileQueryHelper { } final ArrayList<QSTile> tilesToAdd = new ArrayList<>(); - if (mFeatureFlags.isProviderModelSettingEnabled()) { - possibleTiles.remove("cell"); - possibleTiles.remove("wifi"); - } for (String spec : possibleTiles) { // Only add current and stock tiles that can be created from QSFactoryImpl. diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java index 2e771d6fb669..b1cd03c4a2f2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java @@ -116,6 +116,9 @@ public class QSIconViewImpl extends QSIconView { : icon.getInvisibleDrawable(mContext) : null; int padding = icon != null ? icon.getPadding() : 0; if (d != null) { + if (d.getConstantState() != null) { + d = d.getConstantState().newDrawable(); + } d.setAutoMirrored(false); d.setLayoutDirection(getLayoutDirection()); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 4b13015361cc..04f089d31664 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -150,11 +150,7 @@ public class CastTile extends QSTileImpl<BooleanState> { } List<CastDevice> activeDevices = getActiveDevices(); - // We want to pop up the media route selection dialog if we either have no active devices - // (neither routes nor projection), or if we have an active route. In other cases, we assume - // that a projection is active. This is messy, but this tile never correctly handled the - // case where multiple devices were active :-/. - if (activeDevices.isEmpty() || (activeDevices.get(0).tag instanceof RouteInfo)) { + if (willPopDetail()) { mActivityStarter.postQSRunnableDismissingKeyguard(() -> { showDetail(true); }); @@ -163,6 +159,15 @@ public class CastTile extends QSTileImpl<BooleanState> { } } + // We want to pop up the media route selection dialog if we either have no active devices + // (neither routes nor projection), or if we have an active route. In other cases, we assume + // that a projection is active. This is messy, but this tile never correctly handled the + // case where multiple devices were active :-/. + private boolean willPopDetail() { + List<CastDevice> activeDevices = getActiveDevices(); + return activeDevices.isEmpty() || (activeDevices.get(0).tag instanceof RouteInfo); + } + private List<CastDevice> getActiveDevices() { ArrayList<CastDevice> activeDevices = new ArrayList<>(); for (CastDevice device : mController.getCastDevices()) { @@ -234,10 +239,12 @@ public class CastTile extends QSTileImpl<BooleanState> { state.contentDescription = state.contentDescription + "," + mContext.getString(R.string.accessibility_quick_settings_open_details); state.expandedAccessibilityClassName = Button.class.getName(); + state.forceExpandIcon = willPopDetail(); } else { state.state = Tile.STATE_UNAVAILABLE; String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi); state.secondaryLabel = noWifi; + state.forceExpandIcon = false; } state.stateDescription = state.stateDescription + ", " + state.secondaryLabel; mDetailAdapter.updateItems(devices); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 7cb1421e3f0f..cc9e7485dcff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -51,7 +51,9 @@ import com.android.systemui.qs.AlphaControlledSignalTileView; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; @@ -66,15 +68,16 @@ import javax.inject.Inject; /** Quick settings tile: Internet **/ public class InternetTile extends QSTileImpl<SignalState> { private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); - private static final Intent INTERNET_PANEL = - new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY); protected final NetworkController mController; + private final AccessPointController mAccessPointController; private final DataUsageController mDataController; // The last updated tile state, 0: mobile, 1: wifi, 2: ethernet. private int mLastTileState = -1; protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback(); + private final InternetDialogFactory mInternetDialogFactory; + final Handler mHandler; @Inject public InternetTile( @@ -86,11 +89,16 @@ public class InternetTile extends QSTileImpl<SignalState> { StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, - NetworkController networkController + NetworkController networkController, + AccessPointController accessPointController, + InternetDialogFactory internetDialogFactory ) { super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); + mInternetDialogFactory = internetDialogFactory; + mHandler = mainHandler; mController = networkController; + mAccessPointController = accessPointController; mDataController = mController.getMobileDataController(); mController.observe(getLifecycle(), mSignalCallback); } @@ -114,7 +122,9 @@ public class InternetTile extends QSTileImpl<SignalState> { @Override protected void handleClick(@Nullable View view) { - mActivityStarter.postStartActivityDismissingKeyguard(INTERNET_PANEL, 0); + mHandler.post(() -> mInternetDialogFactory.create(true, + mAccessPointController.canConfigMobileData(), + mAccessPointController.canConfigWifi())); } @Override @@ -429,7 +439,7 @@ public class InternetTile extends QSTileImpl<SignalState> { state.icon = ResourceIcon.get(cb.mWifiSignalIconId); } } else if (cb.mNoDefaultNetwork) { - if (cb.mNoNetworksAvailable) { + if (cb.mNoNetworksAvailable || !cb.mEnabled) { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable); } else { @@ -489,7 +499,7 @@ public class InternetTile extends QSTileImpl<SignalState> { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); state.secondaryLabel = r.getString(R.string.status_bar_airplane); } else if (cb.mNoDefaultNetwork) { - if (cb.mNoNetworksAvailable) { + if (cb.mNoNetworksAvailable || !mSignalCallback.mWifiInfo.mEnabled) { state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java new file mode 100644 index 000000000000..99eb5b6519bc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles.dialog; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.text.Html; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.Utils; +import com.android.settingslib.wifi.WifiUtils; +import com.android.systemui.R; +import com.android.wifitrackerlib.WifiEntry; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Adapter for showing Wi-Fi networks. + */ +public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> { + + private static final String TAG = "InternetAdapter"; + private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG"; + private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; + private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller"; + + private final InternetDialogController mInternetDialogController; + private List<WifiEntry> mWifiEntries; + private int mWifiEntriesCount; + + protected View mHolderView; + protected Context mContext; + + public InternetAdapter(InternetDialogController controller) { + mInternetDialogController = controller; + } + + @Override + public InternetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, + int viewType) { + mContext = viewGroup.getContext(); + mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item, + viewGroup, false); + return new InternetViewHolder(mHolderView, mInternetDialogController); + } + + @Override + public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) { + if (mWifiEntries == null || position >= mWifiEntriesCount) { + return; + } + viewHolder.onBind(mWifiEntries.get(position)); + } + + /** + * Updates the Wi-Fi networks. + * + * @param wifiEntries the updated Wi-Fi entries. + * @param wifiEntriesCount the total number of Wi-Fi entries. + */ + public void setWifiEntries(@Nullable List<WifiEntry> wifiEntries, int wifiEntriesCount) { + mWifiEntries = wifiEntries; + mWifiEntriesCount = wifiEntriesCount; + } + + /** + * Gets the total number of Wi-Fi networks. + * + * @return The total number of Wi-Fi entries. + */ + @Override + public int getItemCount() { + return mWifiEntriesCount; + } + + /** + * ViewHolder for binding Wi-Fi view. + */ + static class InternetViewHolder extends RecyclerView.ViewHolder { + + final LinearLayout mContainerLayout; + final LinearLayout mWifiListLayout; + final LinearLayout mWifiNetworkLayout; + final ImageView mWifiIcon; + final TextView mWifiTitleText; + final TextView mWifiSummaryText; + final ImageView mWifiEndIcon; + final Context mContext; + final InternetDialogController mInternetDialogController; + + @VisibleForTesting + protected WifiUtils.InternetIconInjector mWifiIconInjector; + + InternetViewHolder(View view, InternetDialogController internetDialogController) { + super(view); + mContext = view.getContext(); + mInternetDialogController = internetDialogController; + mContainerLayout = view.requireViewById(R.id.internet_container); + mWifiListLayout = view.requireViewById(R.id.wifi_list); + mWifiNetworkLayout = view.requireViewById(R.id.wifi_network_layout); + mWifiIcon = view.requireViewById(R.id.wifi_icon); + mWifiTitleText = view.requireViewById(R.id.wifi_title); + mWifiSummaryText = view.requireViewById(R.id.wifi_summary); + mWifiEndIcon = view.requireViewById(R.id.wifi_end_icon); + mWifiIconInjector = mInternetDialogController.getWifiIconInjector(); + } + + void onBind(@NonNull WifiEntry wifiEntry) { + mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry)); + setWifiNetworkLayout(wifiEntry.getTitle(), + Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY)); + + final int connectedState = wifiEntry.getConnectedState(); + final int security = wifiEntry.getSecurity(); + updateEndIcon(connectedState, security); + + if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) { + mWifiListLayout.setOnClickListener( + v -> mInternetDialogController.launchWifiNetworkDetailsSetting( + wifiEntry.getKey())); + return; + } + mWifiListLayout.setOnClickListener(v -> { + if (wifiEntry.shouldEditBeforeConnect()) { + final Intent intent = new Intent(ACTION_WIFI_DIALOG); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, wifiEntry.getKey()); + intent.putExtra(EXTRA_CONNECT_FOR_CALLER, false); + mContext.startActivity(intent); + } + mInternetDialogController.connect(wifiEntry); + }); + } + + void setWifiNetworkLayout(CharSequence title, CharSequence summary) { + mWifiTitleText.setText(title); + if (TextUtils.isEmpty(summary)) { + mWifiSummaryText.setVisibility(View.GONE); + return; + } + mWifiSummaryText.setVisibility(View.VISIBLE); + mWifiSummaryText.setText(summary); + } + + Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) { + if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) { + return null; + } + final Drawable drawable = mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), + wifiEntry.getLevel()); + if (drawable == null) { + return null; + } + drawable.setTint( + Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorTertiary)); + final AtomicReference<Drawable> shared = new AtomicReference<>(); + shared.set(drawable); + return shared.get(); + } + + void updateEndIcon(int connectedState, int security) { + Drawable drawable = null; + if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) { + drawable = mContext.getDrawable(R.drawable.ic_settings_24dp); + } else if (security != WifiEntry.SECURITY_NONE && security != WifiEntry.SECURITY_OWE) { + drawable = mContext.getDrawable(R.drawable.ic_friction_lock_closed); + } + if (drawable == null) { + mWifiEndIcon.setVisibility(View.GONE); + return; + } + mWifiEndIcon.setVisibility(View.VISIBLE); + mWifiEndIcon.setImageDrawable(drawable); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java new file mode 100644 index 000000000000..b1db8a97b8af --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles.dialog; + +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + +import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA; + +import android.app.AlertDialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Handler; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; +import android.text.Html; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.Switch; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.settingslib.Utils; +import com.android.systemui.Prefs; +import com.android.systemui.R; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.wifitrackerlib.WifiEntry; + +import java.util.List; + +/** + * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks. + */ +@SysUISingleton +public class InternetDialog extends SystemUIDialog implements + InternetDialogController.InternetDialogCallback, Window.Callback { + private static final String TAG = "InternetDialog"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + static final long PROGRESS_DELAY_MS = 2000L; + + private final Handler mHandler; + private final LinearLayoutManager mLayoutManager; + + @VisibleForTesting + protected InternetAdapter mAdapter; + @VisibleForTesting + protected WifiManager mWifiManager; + @VisibleForTesting + protected View mDialogView; + @VisibleForTesting + protected boolean mCanConfigWifi; + + private InternetDialogFactory mInternetDialogFactory; + private SubscriptionManager mSubscriptionManager; + private TelephonyManager mTelephonyManager; + private AlertDialog mAlertDialog; + private UiEventLogger mUiEventLogger; + private Context mContext; + private InternetDialogController mInternetDialogController; + private TextView mInternetDialogTitle; + private TextView mInternetDialogSubTitle; + private View mDivider; + private ProgressBar mProgressBar; + private LinearLayout mInternetDialogLayout; + private LinearLayout mInternetListLayout; + private LinearLayout mConnectedWifListLayout; + private LinearLayout mConnectedWifList; + private LinearLayout mMobileNetworkLayout; + private LinearLayout mMobileNetworkList; + private LinearLayout mTurnWifiOnLayout; + private TextView mWifiToggleTitleText; + private LinearLayout mSeeAllLayout; + private RecyclerView mWifiRecyclerView; + private ImageView mConnectedWifiIcon; + private ImageView mWifiSettingsIcon; + private TextView mConnectedWifiTitleText; + private TextView mConnectedWifiSummaryText; + private ImageView mSignalIcon; + private TextView mMobileTitleText; + private TextView mMobileSummaryText; + private Switch mMobileDataToggle; + private Switch mWiFiToggle; + private Button mDoneButton; + private Drawable mBackgroundOn; + private int mListMaxHeight; + private int mLayoutWidth; + private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private boolean mCanConfigMobileData; + + // Wi-Fi entries + protected WifiEntry mConnectedWifiEntry; + protected int mWifiEntriesCount; + + // Wi-Fi scanning progress bar + protected boolean mIsProgressBarVisible; + protected boolean mIsSearchingHidden; + protected final Runnable mHideProgressBarRunnable = () -> { + setProgressBarVisible(false); + }; + protected Runnable mHideSearchingRunnable = () -> { + mIsSearchingHidden = true; + mInternetDialogSubTitle.setText(getSubtitleText()); + }; + + private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> { + // Set max height for list + if (mInternetDialogLayout.getHeight() > mListMaxHeight) { + ViewGroup.LayoutParams params = mInternetDialogLayout.getLayoutParams(); + params.height = mListMaxHeight; + mInternetDialogLayout.setLayoutParams(params); + } + }; + + public InternetDialog(Context context, InternetDialogFactory internetDialogFactory, + InternetDialogController internetDialogController, boolean canConfigMobileData, + boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger, + @Main Handler handler) { + super(context, R.style.Theme_SystemUI_Dialog_Internet); + if (DEBUG) { + Log.d(TAG, "Init InternetDialog"); + } + mContext = context; + mHandler = handler; + mInternetDialogFactory = internetDialogFactory; + mInternetDialogController = internetDialogController; + mSubscriptionManager = mInternetDialogController.getSubscriptionManager(); + mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId(); + mTelephonyManager = mInternetDialogController.getTelephonyManager(); + mWifiManager = mInternetDialogController.getWifiManager(); + mCanConfigMobileData = canConfigMobileData; + mCanConfigWifi = canConfigWifi; + + mLayoutManager = new LinearLayoutManager(mContext) { + @Override + public boolean canScrollVertically() { + return false; + } + }; + mListMaxHeight = context.getResources().getDimensionPixelSize( + R.dimen.internet_dialog_list_max_height); + mLayoutWidth = context.getResources().getDimensionPixelSize( + R.dimen.internet_dialog_list_max_width); + mUiEventLogger = uiEventLogger; + mAdapter = new InternetAdapter(mInternetDialogController); + if (!aboveStatusBar) { + getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (DEBUG) { + Log.d(TAG, "onCreate"); + } + mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW); + mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog, + null); + final Window window = getWindow(); + final WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.gravity = Gravity.BOTTOM; + // Move down the dialog to overlay the navigation bar. + layoutParams.setFitInsetsTypes( + layoutParams.getFitInsetsTypes() & ~WindowInsets.Type.navigationBars()); + layoutParams.setFitInsetsSides(WindowInsets.Side.all()); + layoutParams.setFitInsetsIgnoringVisibility(true); + window.setAttributes(layoutParams); + window.setContentView(mDialogView); + //Only fix the width for large screen or tablet. + window.setLayout(mContext.getResources().getDimensionPixelSize( + R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT); + window.setWindowAnimations(R.style.Animation_InternetDialog); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + window.addFlags(FLAG_LAYOUT_NO_LIMITS); + + mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog); + mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title); + mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle); + mDivider = mDialogView.requireViewById(R.id.divider); + mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress); + mInternetListLayout = mDialogView.requireViewById(R.id.internet_list); + mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout); + mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list); + mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout); + mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title); + mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout); + mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list); + mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon); + mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title); + mConnectedWifiSummaryText = mDialogView.requireViewById(R.id.wifi_connected_summary); + mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon); + mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout); + mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout); + mDoneButton = mDialogView.requireViewById(R.id.done); + mSignalIcon = mDialogView.requireViewById(R.id.signal_icon); + mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title); + mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary); + mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle); + mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle); + mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on); + mInternetDialogLayout.getViewTreeObserver().addOnGlobalLayoutListener( + mInternetListLayoutListener); + mInternetDialogTitle.setText(getDialogTitleText()); + mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); + + setOnClickListener(); + mTurnWifiOnLayout.setBackground(null); + mWifiRecyclerView.setLayoutManager(mLayoutManager); + mWifiRecyclerView.setAdapter(mAdapter); + } + + @Override + public void onStart() { + super.onStart(); + if (DEBUG) { + Log.d(TAG, "onStart"); + } + mInternetDialogController.onStart(this, mCanConfigWifi); + if (!mCanConfigWifi) { + hideWifiViews(); + } + } + + @VisibleForTesting + void hideWifiViews() { + setProgressBarVisible(false); + mTurnWifiOnLayout.setVisibility(View.GONE); + mConnectedWifListLayout.setVisibility(View.GONE); + mWifiRecyclerView.setVisibility(View.GONE); + mSeeAllLayout.setVisibility(View.GONE); + } + + @Override + public void onStop() { + super.onStop(); + if (DEBUG) { + Log.d(TAG, "onStop"); + } + mHandler.removeCallbacks(mHideProgressBarRunnable); + mHandler.removeCallbacks(mHideSearchingRunnable); + mMobileNetworkLayout.setOnClickListener(null); + mMobileDataToggle.setOnCheckedChangeListener(null); + mConnectedWifListLayout.setOnClickListener(null); + mSeeAllLayout.setOnClickListener(null); + mWiFiToggle.setOnCheckedChangeListener(null); + mDoneButton.setOnClickListener(null); + mInternetDialogController.onStop(); + mInternetDialogFactory.destroyDialog(); + } + + @Override + public void dismissDialog() { + if (DEBUG) { + Log.d(TAG, "dismissDialog"); + } + mInternetDialogFactory.destroyDialog(); + dismiss(); + } + + void updateDialog() { + if (DEBUG) { + Log.d(TAG, "updateDialog"); + } + if (mInternetDialogController.isAirplaneModeEnabled()) { + mInternetDialogSubTitle.setVisibility(View.GONE); + } else { + mInternetDialogSubTitle.setText(getSubtitleText()); + } + setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular()); + + if (!mCanConfigWifi) { + return; + } + + showProgressBar(); + final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked(); + final boolean isWifiEnabled = mWifiManager.isWifiEnabled(); + updateWifiToggle(isWifiEnabled, isDeviceLocked); + updateConnectedWifi(isWifiEnabled, isDeviceLocked); + + final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0) + ? View.GONE : View.VISIBLE; + mWifiRecyclerView.setVisibility(visibility); + mSeeAllLayout.setVisibility(visibility); + } + + private void setOnClickListener() { + mMobileNetworkLayout.setOnClickListener(v -> { + if (mInternetDialogController.isMobileDataEnabled() + && !mInternetDialogController.isDeviceLocked()) { + if (!mInternetDialogController.activeNetworkIsCellular()) { + mInternetDialogController.connectCarrierNetwork(); + } + } + }); + mMobileDataToggle.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + if (!isChecked && shouldShowMobileDialog()) { + showTurnOffMobileDialog(); + } else if (!shouldShowMobileDialog()) { + mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId, + isChecked, false); + } + }); + mConnectedWifListLayout.setOnClickListener(v -> onClickConnectedWifi()); + mSeeAllLayout.setOnClickListener(v -> onClickSeeMoreButton()); + mWiFiToggle.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + buttonView.setChecked(isChecked); + mWifiManager.setWifiEnabled(isChecked); + }); + mDoneButton.setOnClickListener(v -> dismiss()); + } + + private void setMobileDataLayout(boolean isCellularNetwork) { + if (mInternetDialogController.isAirplaneModeEnabled() + || !mInternetDialogController.hasCarrier()) { + mMobileNetworkLayout.setVisibility(View.GONE); + } else { + mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled()); + mMobileNetworkLayout.setVisibility(View.VISIBLE); + mMobileTitleText.setText(getMobileNetworkTitle()); + if (!TextUtils.isEmpty(getMobileNetworkSummary())) { + mMobileSummaryText.setText( + Html.fromHtml(getMobileNetworkSummary(), Html.FROM_HTML_MODE_LEGACY)); + mMobileSummaryText.setVisibility(View.VISIBLE); + } else { + mMobileSummaryText.setVisibility(View.GONE); + } + mSignalIcon.setImageDrawable(getSignalStrengthDrawable()); + if (mInternetDialogController.isNightMode()) { + int titleColor = isCellularNetwork ? mContext.getColor( + R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor( + mContext, android.R.attr.textColorPrimary); + int summaryColor = isCellularNetwork ? mContext.getColor( + R.color.connected_network_secondary_color) : Utils.getColorAttrDefaultColor( + mContext, android.R.attr.textColorSecondary); + + mMobileTitleText.setTextColor(titleColor); + mMobileSummaryText.setTextColor(summaryColor); + } + mMobileNetworkLayout.setBackground(isCellularNetwork ? mBackgroundOn : null); + + mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE); + } + } + + private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) { + mWiFiToggle.setChecked(isWifiEnabled); + if (isDeviceLocked && mInternetDialogController.isNightMode()) { + int titleColor = mConnectedWifiEntry != null ? mContext.getColor( + R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor( + mContext, android.R.attr.textColorPrimary); + mWifiToggleTitleText.setTextColor(titleColor); + } + mTurnWifiOnLayout.setBackground( + (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null); + } + + private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) { + if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) { + mConnectedWifListLayout.setBackground(null); + mConnectedWifListLayout.setVisibility(View.GONE); + return; + } + mConnectedWifListLayout.setVisibility(View.VISIBLE); + mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle()); + mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false)); + mConnectedWifiIcon.setImageDrawable( + mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry)); + if (mInternetDialogController.isNightMode()) { + mConnectedWifiTitleText.setTextColor( + mContext.getColor(R.color.connected_network_primary_color)); + mConnectedWifiSummaryText.setTextColor( + mContext.getColor(R.color.connected_network_secondary_color)); + } + mWifiSettingsIcon.setColorFilter( + mContext.getColor(R.color.connected_network_primary_color)); + mConnectedWifListLayout.setBackground(mBackgroundOn); + } + + void onClickConnectedWifi() { + if (mConnectedWifiEntry == null) { + return; + } + mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey()); + } + + void onClickSeeMoreButton() { + mInternetDialogController.launchNetworkSetting(); + } + + CharSequence getDialogTitleText() { + return mInternetDialogController.getDialogTitleText(); + } + + CharSequence getSubtitleText() { + return mInternetDialogController.getSubtitleText( + mIsProgressBarVisible && !mIsSearchingHidden); + } + + private Drawable getSignalStrengthDrawable() { + return mInternetDialogController.getSignalStrengthDrawable(); + } + + CharSequence getMobileNetworkTitle() { + return mInternetDialogController.getMobileNetworkTitle(); + } + + String getMobileNetworkSummary() { + return mInternetDialogController.getMobileNetworkSummary(); + } + + protected void showProgressBar() { + if (mWifiManager == null || !mWifiManager.isWifiEnabled() + || mInternetDialogController.isDeviceLocked()) { + setProgressBarVisible(false); + return; + } + setProgressBarVisible(true); + if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) { + mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS); + } else if (!mIsSearchingHidden) { + mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS); + } + } + + private void setProgressBarVisible(boolean visible) { + if (mWifiManager.isWifiEnabled() && mAdapter.mHolderView != null + && mAdapter.mHolderView.isAttachedToWindow()) { + mIsProgressBarVisible = true; + } + mIsProgressBarVisible = visible; + mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.GONE); + mDivider.setVisibility(mIsProgressBarVisible ? View.GONE : View.VISIBLE); + mInternetDialogSubTitle.setText(getSubtitleText()); + } + + private boolean shouldShowMobileDialog() { + boolean flag = Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, + false); + if (mInternetDialogController.isMobileDataEnabled() && !flag) { + return true; + } + return false; + } + + private void showTurnOffMobileDialog() { + CharSequence carrierName = getMobileNetworkTitle(); + boolean isInService = mInternetDialogController.isVoiceStateInService(); + if (TextUtils.isEmpty(carrierName) || !isInService) { + carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier); + } + mAlertDialog = new Builder(mContext) + .setTitle(R.string.mobile_data_disable_title) + .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName)) + .setNegativeButton(android.R.string.cancel, (d, w) -> { + mMobileDataToggle.setChecked(true); + }) + .setPositiveButton( + com.android.internal.R.string.alert_windows_notification_turn_off_action, + (d, w) -> { + mInternetDialogController.setMobileDataEnabled(mContext, + mDefaultDataSubId, false, false); + mMobileDataToggle.setChecked(false); + Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true); + }) + .create(); + mAlertDialog.setOnCancelListener(dialog -> mMobileDataToggle.setChecked(true)); + mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + SystemUIDialog.setShowForAllUsers(mAlertDialog, true); + SystemUIDialog.registerDismissListener(mAlertDialog); + SystemUIDialog.setWindowOnTop(mAlertDialog); + mAlertDialog.show(); + } + + @Override + public void onRefreshCarrierInfo() { + mHandler.post(() -> updateDialog()); + } + + @Override + public void onSimStateChanged() { + mHandler.post(() -> updateDialog()); + } + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { + mHandler.post(() -> updateDialog()); + } + + @Override + public void onSubscriptionsChanged(int defaultDataSubId) { + mDefaultDataSubId = defaultDataSubId; + mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); + mHandler.post(() -> updateDialog()); + } + + @Override + public void onServiceStateChanged(ServiceState serviceState) { + mHandler.post(() -> updateDialog()); + } + + @Override + @WorkerThread + public void onDataConnectionStateChanged(int state, int networkType) { + mHandler.post(() -> updateDialog()); + } + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + mHandler.post(() -> updateDialog()); + } + + @Override + public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) { + mHandler.post(() -> updateDialog()); + } + + @Override + @WorkerThread + public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries, + @Nullable WifiEntry connectedEntry) { + mConnectedWifiEntry = connectedEntry; + mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size(); + mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount); + mHandler.post(() -> { + mAdapter.notifyDataSetChanged(); + updateDialog(); + }); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (mAlertDialog != null && !mAlertDialog.isShowing()) { + if (!hasFocus && isShowing()) { + dismiss(); + } + } + } + + public enum InternetDialogEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "The Internet dialog became visible on the screen.") + INTERNET_DIALOG_SHOW(843); + + private final int mId; + + InternetDialogEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java new file mode 100644 index 000000000000..70f52ad5432d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -0,0 +1,942 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.tiles.dialog; + +import static com.android.settingslib.mobile.MobileMappings.getIconKey; +import static com.android.settingslib.mobile.MobileMappings.mapIconSets; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.provider.Settings; +import android.telephony.AccessNetworkConstants; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; + +import com.android.internal.logging.UiEventLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.settingslib.DeviceInfoUtils; +import com.android.settingslib.Utils; +import com.android.settingslib.graph.SignalDrawable; +import com.android.settingslib.mobile.MobileMappings; +import com.android.settingslib.net.SignalStrengthUtil; +import com.android.settingslib.wifi.WifiUtils; +import com.android.systemui.R; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.wifitrackerlib.MergedCarrierEntry; +import com.android.wifitrackerlib.WifiEntry; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.inject.Inject; + +public class InternetDialogController implements WifiEntry.DisconnectCallback, + NetworkController.AccessPointController.AccessPointCallback { + + private static final String TAG = "InternetDialogController"; + private static final String ACTION_NETWORK_PROVIDER_SETTINGS = + "android.settings.NETWORK_PROVIDER_SETTINGS"; + private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; + public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); + public static final int NO_CELL_DATA_TYPE_ICON = 0; + private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off; + private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = + R.string.tap_a_network_to_connect; + private static final int SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS = + R.string.unlock_to_view_networks; + private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS = + R.string.wifi_empty_list_wifi_on; + private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE = + R.string.non_carrier_network_unavailable; + private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE = + R.string.all_network_unavailable; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + static final int MAX_WIFI_ENTRY_COUNT = 4; + + private WifiManager mWifiManager; + private Context mContext; + private SubscriptionManager mSubscriptionManager; + private TelephonyManager mTelephonyManager; + private ConnectivityManager mConnectivityManager; + private TelephonyDisplayInfo mTelephonyDisplayInfo = + new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + private Handler mHandler; + private MobileMappings.Config mConfig = null; + private Executor mExecutor; + private AccessPointController mAccessPointController; + private IntentFilter mConnectionStateFilter; + private InternetDialogCallback mCallback; + private WifiEntry mConnectedEntry; + private int mWifiEntriesCount; + private UiEventLogger mUiEventLogger; + private BroadcastDispatcher mBroadcastDispatcher; + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private GlobalSettings mGlobalSettings; + private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + @VisibleForTesting + protected ActivityStarter mActivityStarter; + @VisibleForTesting + protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; + @VisibleForTesting + protected InternetTelephonyCallback mInternetTelephonyCallback; + @VisibleForTesting + protected WifiUtils.InternetIconInjector mWifiIconInjector; + @VisibleForTesting + protected boolean mCanConfigWifi; + @VisibleForTesting + protected KeyguardStateController mKeyguardStateController; + + private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onRefreshCarrierInfo() { + mCallback.onRefreshCarrierInfo(); + } + + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + mCallback.onSimStateChanged(); + } + }; + + protected List<SubscriptionInfo> getSubscriptionInfo() { + return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); + } + + @Inject + public InternetDialogController(@NonNull Context context, UiEventLogger uiEventLogger, + ActivityStarter starter, AccessPointController accessPointController, + SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, + @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, + @Main Handler handler, @Main Executor mainExecutor, + BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor, + GlobalSettings globalSettings, KeyguardStateController keyguardStateController) { + if (DEBUG) { + Log.d(TAG, "Init InternetDialogController"); + } + mHandler = handler; + mExecutor = mainExecutor; + mContext = context; + mGlobalSettings = globalSettings; + mWifiManager = wifiManager; + mTelephonyManager = telephonyManager; + mConnectivityManager = connectivityManager; + mSubscriptionManager = subscriptionManager; + mBroadcastDispatcher = broadcastDispatcher; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mKeyguardStateController = keyguardStateController; + mConnectionStateFilter = new IntentFilter(); + mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); + mUiEventLogger = uiEventLogger; + mActivityStarter = starter; + mAccessPointController = accessPointController; + mConfig = MobileMappings.Config.readConfig(mContext); + mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext); + } + + void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { + if (DEBUG) { + Log.d(TAG, "onStart"); + } + mCallback = callback; + mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); + mAccessPointController.addAccessPointCallback(this); + mBroadcastDispatcher.registerReceiver(mConnectionStateReceiver, mConnectionStateFilter, + mExecutor); + // Listen the subscription changes + mOnSubscriptionsChangedListener = new InternetOnSubscriptionChangedListener(); + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, + mOnSubscriptionsChangedListener); + mDefaultDataSubId = getDefaultDataSubscriptionId(); + if (DEBUG) { + Log.d(TAG, "Init, SubId: " + mDefaultDataSubId); + } + mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); + mInternetTelephonyCallback = new InternetTelephonyCallback(); + mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback); + // Listen the connectivity changes + mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), new DataConnectivityListener(), mHandler); + mCanConfigWifi = canConfigWifi; + scanWifiAccessPoints(); + } + + void onStop() { + if (DEBUG) { + Log.d(TAG, "onStop"); + } + mBroadcastDispatcher.unregisterReceiver(mConnectionStateReceiver); + mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback); + mSubscriptionManager.removeOnSubscriptionsChangedListener( + mOnSubscriptionsChangedListener); + mAccessPointController.removeAccessPointCallback(this); + mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); + } + + @VisibleForTesting + boolean isAirplaneModeEnabled() { + return mGlobalSettings.getInt(Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } + + @VisibleForTesting + protected int getDefaultDataSubscriptionId() { + return mSubscriptionManager.getDefaultDataSubscriptionId(); + } + + @VisibleForTesting + protected Intent getSettingsIntent() { + return new Intent(ACTION_NETWORK_PROVIDER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } + + protected Intent getWifiDetailsSettingsIntent(String key) { + if (TextUtils.isEmpty(key)) { + if (DEBUG) { + Log.d(TAG, "connected entry's key is empty"); + } + return null; + } + return WifiUtils.getWifiDetailsSettingsIntent(key); + } + + CharSequence getDialogTitleText() { + if (isAirplaneModeEnabled()) { + return mContext.getText(R.string.airplane_mode); + } + return mContext.getText(R.string.quick_settings_internet_label); + } + + CharSequence getSubtitleText(boolean isProgressBarVisible) { + if (isAirplaneModeEnabled()) { + return null; + } + + if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) { + // When the airplane mode is off and Wi-Fi is disabled. + // Sub-Title: Wi-Fi is off + if (DEBUG) { + Log.d(TAG, "Airplane mode off + Wi-Fi off."); + } + return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF); + } + + if (isDeviceLocked()) { + // When the device is locked. + // Sub-Title: Unlock to view networks + if (DEBUG) { + Log.d(TAG, "The device is locked."); + } + return mContext.getText(SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS); + } + + if (mConnectedEntry != null || mWifiEntriesCount > 0) { + return mCanConfigWifi ? mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT) : null; + } + + if (mCanConfigWifi && isProgressBarVisible) { + // When the Wi-Fi scan result callback is received + // Sub-Title: Searching for networks... + return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS); + } + + // Sub-Title: + // show non_carrier_network_unavailable + // - while Wi-Fi on + no Wi-Fi item + // - while Wi-Fi on + no Wi-Fi item + mobile data off + // show all_network_unavailable: + // - while Wi-Fi on + no Wi-Fi item + no carrier item + // - while Wi-Fi on + no Wi-Fi item + service is out of service + // - while Wi-Fi on + no Wi-Fi item + mobile data on + no carrier data. + if (DEBUG) { + Log.d(TAG, "No Wi-Fi item."); + } + if (!hasCarrier() || (!isVoiceStateInService() && !isDataStateInService())) { + if (DEBUG) { + Log.d(TAG, "No carrier or service is out of service."); + } + return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); + } + + if (mCanConfigWifi && !isMobileDataEnabled()) { + if (DEBUG) { + Log.d(TAG, "Mobile data off"); + } + return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); + } + + if (!activeNetworkIsCellular()) { + if (DEBUG) { + Log.d(TAG, "No carrier data."); + } + return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); + } + + if (mCanConfigWifi) { + return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); + } + return null; + } + + Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) { + if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) { + return null; + } + final Drawable drawable = + mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel()); + if (drawable == null) { + return null; + } + drawable.setTint(mContext.getColor(R.color.connected_network_primary_color)); + return drawable; + } + + boolean isNightMode() { + return (mContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + } + + Drawable getSignalStrengthDrawable() { + Drawable drawable = mContext.getDrawable( + R.drawable.ic_signal_strength_zero_bar_no_internet); + try { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null"); + } + return drawable; + } + + if (isDataStateInService() || isVoiceStateInService()) { + AtomicReference<Drawable> shared = new AtomicReference<>(); + shared.set(getSignalStrengthDrawableWithLevel()); + drawable = shared.get(); + } + + drawable.setTint(activeNetworkIsCellular() ? mContext.getColor( + R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor( + mContext, android.R.attr.textColorTertiary)); + } catch (Throwable e) { + e.printStackTrace(); + } + return drawable; + } + + /** + * To get the signal bar icon with level. + * + * @return The Drawable which is a signal bar icon with level. + */ + Drawable getSignalStrengthDrawableWithLevel() { + final SignalStrength strength = mTelephonyManager.getSignalStrength(); + int level = (strength == null) ? 0 : strength.getLevel(); + int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS; + if (mSubscriptionManager != null && shouldInflateSignalStrength(mDefaultDataSubId)) { + level += 1; + numLevels += 1; + } + return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, + !isMobileDataEnabled()); + } + + Drawable getSignalStrengthIcon(Context context, int level, int numLevels, + int iconType, boolean cutOut) { + Log.d(TAG, "getSignalStrengthIcon"); + final SignalDrawable signalDrawable = new SignalDrawable(context); + signalDrawable.setLevel( + SignalDrawable.getState(level, numLevels, cutOut)); + + // Make the network type drawable + final Drawable networkDrawable = + iconType == NO_CELL_DATA_TYPE_ICON + ? EMPTY_DRAWABLE + : context.getResources().getDrawable(iconType, context.getTheme()); + + // Overlay the two drawables + final Drawable[] layers = {networkDrawable, signalDrawable}; + final int iconSize = + context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); + + final LayerDrawable icons = new LayerDrawable(layers); + // Set the network type icon at the top left + icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT); + // Set the signal strength icon at the bottom right + icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT); + icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize); + icons.setTintList(Utils.getColorAttr(context, android.R.attr.textColorTertiary)); + return icons; + } + + private boolean shouldInflateSignalStrength(int subId) { + return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId); + } + + private CharSequence getUniqueSubscriptionDisplayName(int subscriptionId, Context context) { + final Map<Integer, CharSequence> displayNames = getUniqueSubscriptionDisplayNames(context); + return displayNames.getOrDefault(subscriptionId, ""); + } + + private Map<Integer, CharSequence> getUniqueSubscriptionDisplayNames(Context context) { + class DisplayInfo { + public SubscriptionInfo subscriptionInfo; + public CharSequence originalName; + public CharSequence uniqueName; + } + + // Map of SubscriptionId to DisplayName + final Supplier<Stream<DisplayInfo>> originalInfos = + () -> getSubscriptionInfo() + .stream() + .filter(i -> { + // Filter out null values. + return (i != null && i.getDisplayName() != null); + }) + .map(i -> { + DisplayInfo info = new DisplayInfo(); + info.subscriptionInfo = i; + info.originalName = i.getDisplayName().toString().trim(); + return info; + }); + + // A Unique set of display names + Set<CharSequence> uniqueNames = new HashSet<>(); + // Return the set of duplicate names + final Set<CharSequence> duplicateOriginalNames = originalInfos.get() + .filter(info -> !uniqueNames.add(info.originalName)) + .map(info -> info.originalName) + .collect(Collectors.toSet()); + + // If a display name is duplicate, append the final 4 digits of the phone number. + // Creates a mapping of Subscription id to original display name + phone number display name + final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> { + if (duplicateOriginalNames.contains(info.originalName)) { + // This may return null, if the user cannot view the phone number itself. + final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(context, + info.subscriptionInfo); + String lastFourDigits = ""; + if (phoneNumber != null) { + lastFourDigits = (phoneNumber.length() > 4) + ? phoneNumber.substring(phoneNumber.length() - 4) : phoneNumber; + } + + if (TextUtils.isEmpty(lastFourDigits)) { + info.uniqueName = info.originalName; + } else { + info.uniqueName = info.originalName + " " + lastFourDigits; + } + + } else { + info.uniqueName = info.originalName; + } + return info; + }); + + // Check uniqueness a second time. + // We might not have had permission to view the phone numbers. + // There might also be multiple phone numbers whose last 4 digits the same. + uniqueNames.clear(); + final Set<CharSequence> duplicatePhoneNames = uniqueInfos.get() + .filter(info -> !uniqueNames.add(info.uniqueName)) + .map(info -> info.uniqueName) + .collect(Collectors.toSet()); + + return uniqueInfos.get().map(info -> { + if (duplicatePhoneNames.contains(info.uniqueName)) { + info.uniqueName = info.originalName + " " + + info.subscriptionInfo.getSubscriptionId(); + } + return info; + }).collect(Collectors.toMap( + info -> info.subscriptionInfo.getSubscriptionId(), + info -> info.uniqueName)); + } + + CharSequence getMobileNetworkTitle() { + return getUniqueSubscriptionDisplayName(mDefaultDataSubId, mContext); + } + + String getMobileNetworkSummary() { + String description = getNetworkTypeDescription(mContext, mConfig, + mTelephonyDisplayInfo, mDefaultDataSubId); + return getMobileSummary(mContext, mTelephonyManager, description); + } + + /** + * Get currently description of mobile network type. + */ + private String getNetworkTypeDescription(Context context, MobileMappings.Config config, + TelephonyDisplayInfo telephonyDisplayInfo, int subId) { + String iconKey = getIconKey(telephonyDisplayInfo); + + if (mapIconSets(config) == null || mapIconSets(config).get(iconKey) == null) { + if (DEBUG) { + Log.d(TAG, "The description of network type is empty."); + } + return ""; + } + + int resId = mapIconSets(config).get(iconKey).dataContentDescription; + return resId != 0 + ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : ""; + } + + private String getMobileSummary(Context context, TelephonyManager telephonyManager, + String networkTypeDescription) { + if (!isMobileDataEnabled()) { + return context.getString(R.string.mobile_data_off_summary); + } + if (!isDataStateInService()) { + return context.getString(R.string.mobile_data_no_connection); + } + String summary = networkTypeDescription; + if (activeNetworkIsCellular()) { + summary = context.getString(R.string.preference_summary_default_combination, + context.getString(R.string.mobile_data_connection_active), + networkTypeDescription); + } + return summary; + } + + void launchNetworkSetting() { + mCallback.dismissDialog(); + mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0); + } + + void launchWifiNetworkDetailsSetting(String key) { + Intent intent = getWifiDetailsSettingsIntent(key); + if (intent != null) { + mCallback.dismissDialog(); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); + } + } + + void connectCarrierNetwork() { + final MergedCarrierEntry mergedCarrierEntry = + mAccessPointController.getMergedCarrierEntry(); + if (mergedCarrierEntry != null && mergedCarrierEntry.canConnect()) { + mergedCarrierEntry.connect(null /* ConnectCallback */); + } + } + + WifiManager getWifiManager() { + return mWifiManager; + } + + TelephonyManager getTelephonyManager() { + return mTelephonyManager; + } + + SubscriptionManager getSubscriptionManager() { + return mSubscriptionManager; + } + + /** + * @return whether there is the carrier item in the slice. + */ + boolean hasCarrier() { + if (mSubscriptionManager == null) { + if (DEBUG) { + Log.d(TAG, "SubscriptionManager is null, can not check carrier."); + } + return false; + } + + if (isAirplaneModeEnabled() || mTelephonyManager == null + || mSubscriptionManager.getActiveSubscriptionIdList().length <= 0) { + return false; + } + return true; + } + + /** + * Return {@code true} if mobile data is enabled + */ + boolean isMobileDataEnabled() { + if (mTelephonyManager == null || !mTelephonyManager.isDataEnabled()) { + return false; + } + return true; + } + + /** + * Set whether to enable data for {@code subId}, also whether to disable data for other + * subscription + */ + void setMobileDataEnabled(Context context, int subId, boolean enabled, + boolean disableOtherSubscriptions) { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null, can not set mobile data."); + } + return; + } + + if (mSubscriptionManager == null) { + if (DEBUG) { + Log.d(TAG, "SubscriptionManager is null, can not set mobile data."); + } + return; + } + + mTelephonyManager.setDataEnabled(enabled); + if (disableOtherSubscriptions) { + final List<SubscriptionInfo> subInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subInfoList != null) { + for (SubscriptionInfo subInfo : subInfoList) { + // We never disable mobile data for opportunistic subscriptions. + if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { + context.getSystemService(TelephonyManager.class).createForSubscriptionId( + subInfo.getSubscriptionId()).setDataEnabled(false); + } + } + } + } + } + + boolean isDataStateInService() { + final ServiceState serviceState = mTelephonyManager.getServiceState(); + NetworkRegistrationInfo regInfo = + (serviceState == null) ? null : serviceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + return (regInfo == null) ? false : regInfo.isRegistered(); + } + + boolean isVoiceStateInService() { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null, can not detect voice state."); + } + return false; + } + + final ServiceState serviceState = mTelephonyManager.getServiceState(); + return serviceState != null + && serviceState.getState() == serviceState.STATE_IN_SERVICE; + } + + public boolean isDeviceLocked() { + return !mKeyguardStateController.isUnlocked(); + } + + boolean activeNetworkIsCellular() { + if (mConnectivityManager == null) { + if (DEBUG) { + Log.d(TAG, "ConnectivityManager is null, can not check active network."); + } + return false; + } + + final Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if (activeNetwork == null) { + return false; + } + final NetworkCapabilities networkCapabilities = + mConnectivityManager.getNetworkCapabilities(activeNetwork); + if (networkCapabilities == null) { + return false; + } + return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); + } + + boolean connect(WifiEntry ap) { + if (ap == null) { + if (DEBUG) { + Log.d(TAG, "No Wi-Fi ap to connect."); + } + return false; + } + + if (ap.getWifiConfiguration() != null) { + if (DEBUG) { + Log.d(TAG, "connect networkId=" + ap.getWifiConfiguration().networkId); + } + } else { + if (DEBUG) { + Log.d(TAG, "connect to unsaved network " + ap.getTitle()); + } + } + ap.connect(new WifiEntryConnectCallback(mActivityStarter, mContext, ap)); + return false; + } + + static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback { + final ActivityStarter mActivityStarter; + final Context mContext; + final WifiEntry mWifiEntry; + + WifiEntryConnectCallback(ActivityStarter activityStarter, Context context, + WifiEntry connectWifiEntry) { + mActivityStarter = activityStarter; + mContext = context; + mWifiEntry = connectWifiEntry; + } + + @Override + public void onConnectResult(@ConnectStatus int status) { + if (DEBUG) { + Log.d(TAG, "onConnectResult " + status); + } + + if (status == WifiEntry.ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) { + final Intent intent = new Intent("com.android.settings.WIFI_DIALOG") + .putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivityStarter.startActivity(intent, false /* dismissShade */); + } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) { + Toast.makeText(mContext, R.string.wifi_failed_connect_message, + Toast.LENGTH_SHORT).show(); + } else { + if (DEBUG) { + Log.d(TAG, "connect failure reason=" + status); + } + } + } + } + + private void scanWifiAccessPoints() { + if (mCanConfigWifi) { + mAccessPointController.scanForAccessPoints(); + } + } + + @Override + @WorkerThread + public void onAccessPointsChanged(List<WifiEntry> accessPoints) { + if (!mCanConfigWifi) { + return; + } + + if (accessPoints == null || accessPoints.size() == 0) { + mConnectedEntry = null; + mWifiEntriesCount = 0; + if (mCallback != null) { + mCallback.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */); + } + return; + } + + boolean hasConnectedWifi = false; + final int accessPointSize = accessPoints.size(); + for (int i = 0; i < accessPointSize; i++) { + WifiEntry wifiEntry = accessPoints.get(i); + if (wifiEntry.isDefaultNetwork() && wifiEntry.hasInternetAccess()) { + mConnectedEntry = wifiEntry; + hasConnectedWifi = true; + break; + } + } + if (!hasConnectedWifi) { + mConnectedEntry = null; + } + + int count = MAX_WIFI_ENTRY_COUNT; + if (hasCarrier()) { + count -= 1; + } + if (hasConnectedWifi) { + count -= 1; + } + final List<WifiEntry> wifiEntries = accessPoints.stream() + .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork() + || !wifiEntry.hasInternetAccess())) + .limit(count) + .collect(Collectors.toList()); + mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size(); + + if (mCallback != null) { + mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry); + } + } + + @Override + public void onSettingsActivityTriggered(Intent settingsIntent) { + } + + @Override + public void onDisconnectResult(int status) { + } + + private class InternetTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.DataConnectionStateListener, + TelephonyCallback.DisplayInfoListener, + TelephonyCallback.ServiceStateListener, + TelephonyCallback.SignalStrengthsListener { + + @Override + public void onServiceStateChanged(@NonNull ServiceState serviceState) { + mCallback.onServiceStateChanged(serviceState); + } + + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + mCallback.onDataConnectionStateChanged(state, networkType); + } + + @Override + public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) { + mCallback.onSignalStrengthsChanged(signalStrength); + } + + @Override + public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) { + mTelephonyDisplayInfo = telephonyDisplayInfo; + mCallback.onDisplayInfoChanged(telephonyDisplayInfo); + } + } + + private class InternetOnSubscriptionChangedListener + extends SubscriptionManager.OnSubscriptionsChangedListener { + InternetOnSubscriptionChangedListener() { + super(); + } + + @Override + public void onSubscriptionsChanged() { + updateListener(); + } + } + + private class DataConnectivityListener extends ConnectivityManager.NetworkCallback { + @Override + @WorkerThread + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) { + if (mCanConfigWifi) { + for (int transport : networkCapabilities.getTransportTypes()) { + if (transport == NetworkCapabilities.TRANSPORT_WIFI) { + scanWifiAccessPoints(); + break; + } + } + } + final Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if (activeNetwork != null && activeNetwork.equals(network)) { + // update UI + mCallback.onCapabilitiesChanged(network, networkCapabilities); + } + } + } + + private final BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { + if (DEBUG) { + Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"); + } + updateListener(); + } + } + }; + + private void updateListener() { + int defaultDataSubId = getDefaultDataSubscriptionId(); + if (mDefaultDataSubId == getDefaultDataSubscriptionId()) { + if (DEBUG) { + Log.d(TAG, "DDS: no change"); + } + return; + } + + mDefaultDataSubId = defaultDataSubId; + if (DEBUG) { + Log.d(TAG, "DDS: defaultDataSubId:" + mDefaultDataSubId); + } + if (SubscriptionManager.isUsableSubscriptionId(mDefaultDataSubId)) { + mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback); + mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); + mTelephonyManager.registerTelephonyCallback(mHandler::post, + mInternetTelephonyCallback); + mCallback.onSubscriptionsChanged(mDefaultDataSubId); + } + } + + public WifiUtils.InternetIconInjector getWifiIconInjector() { + return mWifiIconInjector; + } + + interface InternetDialogCallback { + + void onRefreshCarrierInfo(); + + void onSimStateChanged(); + + void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities); + + void onSubscriptionsChanged(int defaultDataSubId); + + void onServiceStateChanged(ServiceState serviceState); + + void onDataConnectionStateChanged(int state, int networkType); + + void onSignalStrengthsChanged(SignalStrength signalStrength); + + void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo); + + void dismissDialog(); + + void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries, + @Nullable WifiEntry connectedEntry); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt new file mode 100644 index 000000000000..11c6980678b1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles.dialog + +import android.content.Context +import android.os.Handler +import android.util.Log +import com.android.internal.logging.UiEventLogger +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import javax.inject.Inject + +private const val TAG = "InternetDialogFactory" +private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) + +/** + * Factory to create [InternetDialog] objects. + */ +@SysUISingleton +class InternetDialogFactory @Inject constructor( + @Main private val handler: Handler, + private val internetDialogController: InternetDialogController, + private val context: Context, + private val uiEventLogger: UiEventLogger +) { + companion object { + var internetDialog: InternetDialog? = null + } + + /** Creates a [InternetDialog]. */ + fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) { + if (internetDialog != null) { + if (DEBUG) { + Log.d(TAG, "InternetDialog is showing, do not create it twice.") + } + return + } else { + internetDialog = InternetDialog(context, this, internetDialogController, + canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler) + internetDialog?.show() + } + } + + fun destroyDialog() { + if (DEBUG) { + Log.d(TAG, "destroyDialog") + } + internetDialog = null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java new file mode 100644 index 000000000000..6aaba997faad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java @@ -0,0 +1,14 @@ +package com.android.systemui.qs.tiles.dialog; + +import android.content.Context; +import android.util.FeatureFlagUtils; + +public class InternetDialogUtil { + + public static boolean isProviderModelEnabled(Context context) { + if (context == null) { + return false; + } + return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index 0eaef72ae29b..31d51f1d1a60 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -154,6 +154,7 @@ public class LongScreenshotActivity extends Activity { @Override public void onStart() { super.onStart(); + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_STARTED); if (mPreview.getDrawable() != null) { // We already have an image, so no need to try to load again. @@ -245,6 +246,8 @@ public class LongScreenshotActivity extends Activity { } private void onCachedImageLoaded(ImageLoader.Result imageResult) { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED); + BitmapDrawable drawable = new BitmapDrawable(getResources(), imageResult.bitmap); mPreview.setImageDrawable(drawable); mPreview.setAlpha(1f); @@ -282,6 +285,8 @@ public class LongScreenshotActivity extends Activity { finish(); } if (isFinishing()) { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_FINISHED); + if (mScrollCaptureResponse != null) { mScrollCaptureResponse.close(); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 16872b08b9c8..8def475c192c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -33,6 +33,7 @@ import static java.util.Objects.requireNonNull; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.annotation.MainThread; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -261,6 +262,7 @@ public class ScreenshotController { private Bitmap mScreenBitmap; private SaveImageInBackgroundTask mSaveInBgTask; private boolean mScreenshotTakenInPortrait; + private boolean mBlockAttach; private Animator mScreenshotAnimation; private RequestCallback mCurrentRequestCallback; @@ -559,8 +561,8 @@ public class ScreenshotController { mScreenshotView.reset(); } - mScreenshotView.updateOrientation(mWindowManager.getCurrentWindowMetrics() - .getWindowInsets().getDisplayCutout()); + mScreenshotView.updateOrientation( + mWindowManager.getCurrentWindowMetrics().getWindowInsets()); mScreenBitmap = screenshot; @@ -594,9 +596,8 @@ public class ScreenshotController { // Delay scroll capture eval a bit to allow the underlying activity // to set up in the new orientation. mScreenshotHandler.postDelayed(this::requestScrollCapture, 150); - mScreenshotView.updateDisplayCutoutMargins( - mWindowManager.getCurrentWindowMetrics().getWindowInsets() - .getDisplayCutout()); + mScreenshotView.updateInsets( + mWindowManager.getCurrentWindowMetrics().getWindowInsets()); // screenshot animation calculations won't be valid anymore, so just end if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) { mScreenshotAnimation.end(); @@ -660,7 +661,7 @@ public class ScreenshotController { + mLastScrollCaptureResponse.getWindowTitle() + "]"); final ScrollCaptureResponse response = mLastScrollCaptureResponse; - mScreenshotView.showScrollChip(/* onClick */ () -> { + mScreenshotView.showScrollChip(response.getPackageName(), /* onClick */ () -> { DisplayMetrics displayMetrics = new DisplayMetrics(); getDefaultDisplay().getRealMetrics(displayMetrics); Bitmap newScreenshot = captureScreenshot( @@ -732,6 +733,7 @@ public class ScreenshotController { new ViewTreeObserver.OnWindowAttachListener() { @Override public void onWindowAttached() { + mBlockAttach = false; decorView.getViewTreeObserver().removeOnWindowAttachListener(this); action.run(); } @@ -748,14 +750,16 @@ public class ScreenshotController { mWindow.setContentView(contentView); } + @MainThread private void attachWindow() { View decorView = mWindow.getDecorView(); - if (decorView.isAttachedToWindow()) { + if (decorView.isAttachedToWindow() || mBlockAttach) { return; } if (DEBUG_WINDOW) { Log.d(TAG, "attachWindow"); } + mBlockAttach = true; mWindowManager.addView(decorView, mWindowLayoutParams); decorView.requestApplyInsets(); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java index 5cf018813133..169b28c6b373 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java @@ -71,7 +71,19 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "User has shared a long screenshot") SCREENSHOT_LONG_SCREENSHOT_SHARE(689), @UiEvent(doc = "User has sent a long screenshot to the editor") - SCREENSHOT_LONG_SCREENSHOT_EDIT(690); + SCREENSHOT_LONG_SCREENSHOT_EDIT(690), + @UiEvent(doc = "A long screenshot capture has started") + SCREENSHOT_LONG_SCREENSHOT_STARTED(880), + @UiEvent(doc = "The long screenshot capture failed") + SCREENSHOT_LONG_SCREENSHOT_FAILURE(881), + @UiEvent(doc = "The long screenshot capture completed successfully") + SCREENSHOT_LONG_SCREENSHOT_COMPLETED(882), + @UiEvent(doc = "Long screenshot editor activity started") + SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_STARTED(889), + @UiEvent(doc = "Long screenshot editor activity loaded a previously saved screenshot") + SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_CACHED_IMAGE_LOADED(890), + @UiEvent(doc = "Long screenshot editor activity finished") + SCREENSHOT_LONG_SCREENSHOT_ACTIVITY_FINISHED(891); private final int mId; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index e9e62f26a10e..dfb39e300450 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -118,8 +118,8 @@ public class ScreenshotView extends FrameLayout implements private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234; private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400; private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100; - private static final long SCREENSHOT_DISMISS_Y_DURATION_MS = 350; - private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 183; + private static final long SCREENSHOT_DISMISS_X_DURATION_MS = 350; + private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 350; private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f; private static final float ROUNDED_CORNER_RADIUS = .25f; @@ -242,19 +242,21 @@ public class ScreenshotView extends FrameLayout implements /** * Called to display the scroll action chip when support is detected. * + * @param packageName the owning package of the window to be captured * @param onClick the action to take when the chip is clicked. */ - public void showScrollChip(Runnable onClick) { + public void showScrollChip(String packageName, Runnable onClick) { if (DEBUG_SCROLL) { Log.d(TAG, "Showing Scroll option"); } - mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION); + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION, 0, packageName); mScrollChip.setVisibility(VISIBLE); mScrollChip.setOnClickListener((v) -> { if (DEBUG_INPUT) { Log.d(TAG, "scroll chip tapped"); } - mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED); + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_REQUESTED, 0, + packageName); onClick.run(); }); } @@ -414,21 +416,30 @@ public class ScreenshotView extends FrameLayout implements mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets)); } - void updateDisplayCutoutMargins(DisplayCutout cutout) { + void updateInsets(WindowInsets insets) { int orientation = mContext.getResources().getConfiguration().orientation; mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT); FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mScreenshotStatic.getLayoutParams(); + DisplayCutout cutout = insets.getDisplayCutout(); + Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars()); if (cutout == null) { - p.setMargins(0, 0, 0, 0); + p.setMargins(0, 0, 0, navBarInsets.bottom); } else { Insets waterfall = cutout.getWaterfallInsets(); if (mOrientationPortrait) { - p.setMargins(waterfall.left, Math.max(cutout.getSafeInsetTop(), waterfall.top), - waterfall.right, Math.max(cutout.getSafeInsetBottom(), waterfall.bottom)); + p.setMargins( + waterfall.left, + Math.max(cutout.getSafeInsetTop(), waterfall.top), + waterfall.right, + Math.max(cutout.getSafeInsetBottom(), + Math.max(navBarInsets.bottom, waterfall.bottom))); } else { - p.setMargins(Math.max(cutout.getSafeInsetLeft(), waterfall.left), waterfall.top, - Math.max(cutout.getSafeInsetRight(), waterfall.right), waterfall.bottom); + p.setMargins( + Math.max(cutout.getSafeInsetLeft(), waterfall.left), + waterfall.top, + Math.max(cutout.getSafeInsetRight(), waterfall.right), + Math.max(navBarInsets.bottom, waterfall.bottom)); } } mStaticLeftMargin = p.leftMargin; @@ -436,10 +447,10 @@ public class ScreenshotView extends FrameLayout implements mScreenshotStatic.requestLayout(); } - void updateOrientation(DisplayCutout cutout) { + void updateOrientation(WindowInsets insets) { int orientation = mContext.getResources().getConfiguration().orientation; mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT); - updateDisplayCutoutMargins(cutout); + updateInsets(insets); int screenshotFixedSize = mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_x_scale); ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams(); @@ -978,7 +989,6 @@ public class ScreenshotView extends FrameLayout implements mScrollingScrim.setVisibility(View.GONE); mScrollablePreview.setVisibility(View.GONE); mScreenshotStatic.setTranslationX(0); - mScreenshotPreview.setTranslationY(0); mScreenshotPreview.setContentDescription( mContext.getResources().getString(R.string.screenshot_preview_description)); mScreenshotPreview.setOnClickListener(null); @@ -994,9 +1004,6 @@ public class ScreenshotView extends FrameLayout implements mSmartChips.clear(); mQuickShareChip = null; setAlpha(1); - mDismissButton.setTranslationY(0); - mActionsContainer.setTranslationY(0); - mActionsContainerBackground.setTranslationY(0); mScreenshotSelectorView.stop(); } @@ -1024,22 +1031,19 @@ public class ScreenshotView extends FrameLayout implements setAlpha(1 - animation.getAnimatedFraction()); }); - ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1); - yAnim.setInterpolator(mAccelerateInterpolator); - yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS); - float screenshotStartY = mScreenshotPreview.getTranslationY(); - float dismissStartY = mDismissButton.getTranslationY(); - yAnim.addUpdateListener(animation -> { - float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction()); - mScreenshotPreview.setTranslationY(screenshotStartY + yDelta); - mScreenshotPreviewBorder.setTranslationY(screenshotStartY + yDelta); - mDismissButton.setTranslationY(dismissStartY + yDelta); - mActionsContainer.setTranslationY(yDelta); - mActionsContainerBackground.setTranslationY(yDelta); + ValueAnimator xAnim = ValueAnimator.ofFloat(0, 1); + xAnim.setInterpolator(mAccelerateInterpolator); + xAnim.setDuration(SCREENSHOT_DISMISS_X_DURATION_MS); + float deltaX = mDirectionLTR + ? -1 * (mScreenshotPreviewBorder.getX() + mScreenshotPreviewBorder.getWidth()) + : (mDisplayMetrics.widthPixels - mScreenshotPreviewBorder.getX()); + xAnim.addUpdateListener(animation -> { + float currXDelta = MathUtils.lerp(0, deltaX, animation.getAnimatedFraction()); + mScreenshotStatic.setTranslationX(currXDelta); }); AnimatorSet animSet = new AnimatorSet(); - animSet.play(yAnim).with(alphaAnim); + animSet.play(xAnim).with(alphaAnim); return animSet; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java index 6dc68746e3ec..ef7355a09fbf 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java @@ -28,6 +28,7 @@ import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.concurrent.futures.CallbackToFutureAdapter.Completer; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult; import com.android.systemui.screenshot.ScrollCaptureClient.Session; @@ -61,6 +62,7 @@ public class ScrollCaptureController { private final Context mContext; private final Executor mBgExecutor; private final ImageTileSet mImageTileSet; + private final UiEventLogger mEventLogger; private final ScrollCaptureClient mClient; private Completer<LongScreenshot> mCaptureCompleter; @@ -69,6 +71,7 @@ public class ScrollCaptureController { private Session mSession; private ListenableFuture<CaptureResult> mTileFuture; private ListenableFuture<Void> mEndFuture; + private String mWindowOwner; static class LongScreenshot { private final ImageTileSet mImageTileSet; @@ -135,11 +138,12 @@ public class ScrollCaptureController { @Inject ScrollCaptureController(Context context, @Background Executor bgExecutor, - ScrollCaptureClient client, ImageTileSet imageTileSet) { + ScrollCaptureClient client, ImageTileSet imageTileSet, UiEventLogger logger) { mContext = context; mBgExecutor = bgExecutor; mClient = client; mImageTileSet = imageTileSet; + mEventLogger = logger; } @VisibleForTesting @@ -157,6 +161,7 @@ public class ScrollCaptureController { ListenableFuture<LongScreenshot> run(ScrollCaptureResponse response) { return CallbackToFutureAdapter.getFuture(completer -> { mCaptureCompleter = completer; + mWindowOwner = response.getPackageName(); mBgExecutor.execute(() -> { float maxPages = Settings.Secure.getFloat(mContext.getContentResolver(), SETTING_KEY_MAX_PAGES, MAX_PAGES_DEFAULT); @@ -173,11 +178,13 @@ public class ScrollCaptureController { if (LogConfig.DEBUG_SCROLL) { Log.d(TAG, "got session " + mSession); } + mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_STARTED, 0, mWindowOwner); requestNextTile(0); } catch (InterruptedException | ExecutionException e) { // Failure to start, propagate to caller Log.e(TAG, "session start failed!"); mCaptureCompleter.setException(e); + mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_FAILURE, 0, mWindowOwner); } } @@ -297,6 +304,11 @@ public class ScrollCaptureController { if (LogConfig.DEBUG_SCROLL) { Log.d(TAG, "finishCapture()"); } + if (mImageTileSet.getHeight() > 0) { + mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_COMPLETED, 0, mWindowOwner); + } else { + mEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_FAILURE, 0, mWindowOwner); + } mEndFuture = mSession.end(); mEndFuture.addListener(() -> { if (LogConfig.DEBUG_SCROLL) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 8e52b0da54ef..50911d162113 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -290,8 +290,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, - boolean requireConfirmation, int userId, String opPackageName, - long operationId, @BiometricMultiSensorMode int multiSensorConfig) { + boolean requireConfirmation, int userId, long operationId, String opPackageName, + long requestId, @BiometricMultiSensorMode int multiSensorConfig) { } /** @see IStatusBar#onBiometricAuthenticated() */ @@ -843,7 +843,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, + int userId, long operationId, String opPackageName, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); @@ -855,6 +855,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi1 = userId; args.arg6 = opPackageName; args.arg7 = operationId; + args.arg8 = requestId; args.argi2 = multiSensorConfig; mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args) .sendToTarget(); @@ -1312,8 +1313,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< (boolean) someArgs.arg4 /* credentialAllowed */, (boolean) someArgs.arg5 /* requireConfirmation */, someArgs.argi1 /* userId */, - (String) someArgs.arg6 /* opPackageName */, (long) someArgs.arg7 /* operationId */, + (String) someArgs.arg6 /* opPackageName */, + (long) someArgs.arg8 /* requestId */, someArgs.argi2 /* multiSensorConfig */); } someArgs.recycle(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 503b5c0ee4b0..445715e138ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -723,15 +723,13 @@ public class KeyguardIndicationController { } protected String computePowerIndication() { - if (mPowerCharged) { - return mContext.getResources().getString(R.string.keyguard_charged); - } - int chargingId; - String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); if (mBatteryOverheated) { chargingId = R.string.keyguard_plugged_in_charging_limited; + String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); return mContext.getResources().getString(chargingId, percentage); + } else if (mPowerCharged) { + return mContext.getResources().getString(R.string.keyguard_charged); } final boolean hasChargingTime = mChargingTimeRemaining > 0; @@ -759,6 +757,7 @@ public class KeyguardIndicationController { : R.string.keyguard_plugged_in_wireless; } + String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); if (hasChargingTime) { String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( mContext, mChargingTimeRemaining); @@ -811,17 +810,12 @@ public class KeyguardIndicationController { mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); } } else if (mKeyguardUpdateMonitor.isScreenOn()) { - if (mKeyguardUpdateMonitor.isUdfpsAvailable()) { - showTransientIndication(mContext.getString(R.string.keyguard_unlock_press), - false /* isError */, true /* hideOnScreenOff */); - } else { - showTransientIndication(mContext.getString(R.string.keyguard_unlock), - false /* isError */, true /* hideOnScreenOff */); - } + showTransientIndication(mContext.getString(R.string.keyguard_unlock), + false /* isError */, true /* hideOnScreenOff */); } } - private void showTryFingerprintMsg() { + private void showTryFingerprintMsg(String a11yString) { if (mKeyguardUpdateMonitor.isUdfpsAvailable()) { // if udfps available, there will always be a tappable affordance to unlock // For example, the lock icon @@ -833,6 +827,11 @@ public class KeyguardIndicationController { } else { showTransientIndication(R.string.keyguard_try_fingerprint); } + + // Although we suppress face auth errors visually, we still announce them for a11y + if (!TextUtils.isEmpty(a11yString)) { + mLockScreenIndicationView.announceForAccessibility(a11yString); + } } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -913,7 +912,7 @@ public class KeyguardIndicationController { } else if (mKeyguardUpdateMonitor.isScreenOn()) { if (biometricSourceType == BiometricSourceType.FACE && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) { - showTryFingerprintMsg(); + showTryFingerprintMsg(helpString); return; } showTransientIndication(helpString, false /* isError */, showActionToUnlock); @@ -933,7 +932,7 @@ public class KeyguardIndicationController { && shouldSuppressFaceMsgAndShowTryFingerprintMsg() && !mStatusBarKeyguardViewManager.isBouncerShowing() && mKeyguardUpdateMonitor.isScreenOn()) { - showTryFingerprintMsg(); + showTryFingerprintMsg(errString); return; } if (msgId == FaceManager.FACE_ERROR_TIMEOUT) { @@ -942,7 +941,7 @@ public class KeyguardIndicationController { if (!mStatusBarKeyguardViewManager.isBouncerShowing() && mKeyguardUpdateMonitor.isUdfpsEnrolled() && mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { - showTryFingerprintMsg(); + showTryFingerprintMsg(errString); } else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { mStatusBarKeyguardViewManager.showBouncerMessage( mContext.getResources().getString(R.string.keyguard_unlock_press), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index 538db6168408..21ed9da896a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -149,7 +149,10 @@ class PowerButtonReveal( */ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, attrs) { - lateinit var revealAmountListener: Consumer<Float> + /** + * Listener that is called if the scrim's opaqueness changes + */ + lateinit var isScrimOpaqueChangedListener: Consumer<Boolean> /** * How much of the underlying views are revealed, in percent. 0 means they will be completely @@ -161,7 +164,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, field = value revealEffect.setRevealAmountOnScrim(value, this) - revealAmountListener.accept(value) + updateScrimOpaque() invalidate() } } @@ -201,6 +204,31 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, } /** + * Is the scrim currently fully opaque + */ + var isScrimOpaque = false + private set(value) { + if (field != value) { + field = value + isScrimOpaqueChangedListener.accept(field) + } + } + + private fun updateScrimOpaque() { + isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE + } + + override fun setAlpha(alpha: Float) { + super.setAlpha(alpha) + updateScrimOpaque() + } + + override fun setVisibility(visibility: Int) { + super.setVisibility(visibility) + updateScrimOpaque() + } + + /** * Paint used to draw a transparent-to-white radial gradient. This will be scaled and translated * via local matrix in [onDraw] so we never need to construct a new shader. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index b8334272c157..2a8771e96e7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -78,7 +78,8 @@ class NotificationShadeDepthController @Inject constructor( private var keyguardAnimator: Animator? = null private var notificationAnimator: Animator? = null private var updateScheduled: Boolean = false - private var shadeExpansion = 0f + @VisibleForTesting + var shadeExpansion = 0f private var isClosed: Boolean = true private var isOpen: Boolean = false private var isBlurred: Boolean = false @@ -92,6 +93,9 @@ class NotificationShadeDepthController @Inject constructor( // Only for dumpsys private var lastAppliedBlur = 0 + // Shade expansion offset that happens when pulling down on a HUN. + var panelPullDownMinFraction = 0f + var shadeAnimation = DepthAnimation() @VisibleForTesting @@ -181,7 +185,8 @@ class NotificationShadeDepthController @Inject constructor( if (shouldApplyShadeBlur()) shadeExpansion else 0f, false)) var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION + animationRadius * ANIMATION_BLUR_FRACTION) - val qsExpandedRatio = qsPanelExpansion * shadeExpansion + val qsExpandedRatio = Interpolators.getNotificationScrimAlpha(qsPanelExpansion, + false /* notification */) * shadeExpansion combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio)) combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) @@ -311,8 +316,10 @@ class NotificationShadeDepthController @Inject constructor( /** * Update blurs when pulling down the shade */ - override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) { + override fun onPanelExpansionChanged(rawExpansion: Float, tracking: Boolean) { val timestamp = SystemClock.elapsedRealtimeNanos() + val expansion = MathUtils.saturate( + (rawExpansion - panelPullDownMinFraction) / (1f - panelPullDownMinFraction)) if (shadeExpansion == expansion && prevTracking == tracking) { prevTimestamp = timestamp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java index f0d779ce1e0f..6ea79af8b9ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java @@ -182,10 +182,10 @@ public interface NotificationShadeWindowController extends RemoteInputController default void setFaceAuthDisplayBrightness(float brightness) {} /** - * How much {@link LightRevealScrim} obscures the UI. - * @param amount 0 when opaque, 1 when not transparent + * If {@link LightRevealScrim} obscures the UI. + * @param opaque if the scrim is opaque */ - default void setLightRevealScrimAmount(float amount) {} + default void setLightRevealScrimOpaque(boolean opaque) {} /** * Custom listener to pipe data back to plugins about whether or not the status bar would be diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt index 4a467ce3c987..d01fc93ee84c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt @@ -104,7 +104,7 @@ class ChargingRippleView(context: Context?, attrs: AttributeSet?) : View(context // the active effect area. Values here should be kept in sync with the // animation implementation in the ripple shader. val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) * - (1 - rippleShader.progress)) * radius * 1.5f + (1 - rippleShader.progress)) * radius * 2 canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index 71546ae07ffc..d432f8f308dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -45,6 +45,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.util.concurrency.Execution import com.android.systemui.util.settings.SecureSettings import java.lang.RuntimeException @@ -67,6 +68,7 @@ class LockscreenSmartspaceController @Inject constructor( private val contentResolver: ContentResolver, private val configurationController: ConfigurationController, private val statusBarStateController: StatusBarStateController, + private val deviceProvisionedController: DeviceProvisionedController, private val execution: Execution, @Main private val uiExecutor: Executor, @Main private val handler: Handler, @@ -83,6 +85,55 @@ class LockscreenSmartspaceController @Inject constructor( private var showSensitiveContentForManagedUser = false private var managedUserHandle: UserHandle? = null + private val deviceProvisionedListener = + object : DeviceProvisionedController.DeviceProvisionedListener { + override fun onDeviceProvisionedChanged() { + connectSession() + } + + override fun onUserSetupChanged() { + connectSession() + } + } + + private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets -> + execution.assertIsMainThread() + val filteredTargets = targets.filter(::filterSmartspaceTarget) + plugin?.onTargetsAvailable(filteredTargets) + } + + private val userTrackerCallback = object : UserTracker.Callback { + override fun onUserChanged(newUser: Int, userContext: Context) { + execution.assertIsMainThread() + reloadSmartspace() + } + } + + private val settingsObserver = object : ContentObserver(handler) { + override fun onChange(selfChange: Boolean, uri: Uri?) { + execution.assertIsMainThread() + reloadSmartspace() + } + } + + private val configChangeListener = object : ConfigurationController.ConfigurationListener { + override fun onThemeChanged() { + execution.assertIsMainThread() + updateTextColorFromWallpaper() + } + } + + private val statusBarStateListener = object : StatusBarStateController.StateListener { + override fun onDozeAmountChanged(linear: Float, eased: Float) { + execution.assertIsMainThread() + smartspaceView.setDozeAmount(eased) + } + } + + init { + deviceProvisionedController.addCallback(deviceProvisionedListener) + } + fun isEnabled(): Boolean { execution.assertIsMainThread() @@ -144,10 +195,20 @@ class LockscreenSmartspaceController @Inject constructor( if (plugin == null || session != null) { return } - val session = smartspaceManager.createSmartspaceSession( + + // Only connect after the device is fully provisioned to avoid connection caching + // issues + if (!deviceProvisionedController.isDeviceProvisioned() || + !deviceProvisionedController.isCurrentUserSetup()) { + return + } + + val newSession = smartspaceManager.createSmartspaceSession( SmartspaceConfig.Builder(context, "lockscreen").build()) - session.addOnTargetsAvailableListener(uiExecutor, sessionListener) + newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener) + this.session = newSession + deviceProvisionedController.removeCallback(deviceProvisionedListener) userTracker.addCallback(userTrackerCallback, uiExecutor) contentResolver.registerContentObserver( secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS), @@ -158,8 +219,6 @@ class LockscreenSmartspaceController @Inject constructor( configurationController.addCallback(configChangeListener) statusBarStateController.addCallback(statusBarStateListener) - this.session = session - reloadSmartspace() } @@ -198,43 +257,6 @@ class LockscreenSmartspaceController @Inject constructor( plugin?.unregisterListener(listener) } - private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets -> - execution.assertIsMainThread() - val filteredTargets = targets.filter(::filterSmartspaceTarget) - plugin?.onTargetsAvailable(filteredTargets) - } - - private val userTrackerCallback = object : UserTracker.Callback { - override fun onUserChanged(newUser: Int, userContext: Context) { - execution.assertIsMainThread() - reloadSmartspace() - } - - override fun onProfilesChanged(profiles: List<UserInfo>) { - } - } - - private val settingsObserver = object : ContentObserver(handler) { - override fun onChange(selfChange: Boolean, uri: Uri?) { - execution.assertIsMainThread() - reloadSmartspace() - } - } - - private val configChangeListener = object : ConfigurationController.ConfigurationListener { - override fun onThemeChanged() { - execution.assertIsMainThread() - updateTextColorFromWallpaper() - } - } - - private val statusBarStateListener = object : StatusBarStateController.StateListener { - override fun onDozeAmountChanged(linear: Float, eased: Float) { - execution.assertIsMainThread() - smartspaceView.setDozeAmount(eased) - } - } - private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean { return when (t.userHandle) { userTracker.userHandle -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java index dba3401cc28e..9c755e970a0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java @@ -85,23 +85,26 @@ public abstract class StackScrollerDecorView extends ExpandableView { } /** - * Set the content of this view to be visible in an animated way. - * - * @param contentVisible True if the content should be visible or false if it should be hidden. + * @param visible True if we should animate contents visible */ - public void setContentVisible(boolean contentVisible) { - setContentVisible(contentVisible, true /* animate */); + public void setContentVisible(boolean visible) { + setContentVisible(visible, true /* animate */, null /* runAfter */); } + /** - * Set the content of this view to be visible. - * @param contentVisible True if the content should be visible or false if it should be hidden. - * @param animate Should an animation be performed. + * @param visible True if the contents should be visible + * @param animate True if we should fade to new visibility + * @param runAfter Runnable to run after visibility updates */ - private void setContentVisible(boolean contentVisible, boolean animate) { - if (mContentVisible != contentVisible) { + public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) { + if (mContentVisible != visible) { mContentAnimating = animate; - mContentVisible = contentVisible; - setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable); + mContentVisible = visible; + Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> { + mContentVisibilityEndRunnable.run(); + runAfter.run(); + }; + setViewVisible(mContent, visible, animate, endRunnable); } if (!mContentAnimating) { @@ -113,6 +116,10 @@ public abstract class StackScrollerDecorView extends ExpandableView { return mContentVisible; } + public void setVisible(boolean nowVisible, boolean animate) { + setVisible(nowVisible, animate, null); + } + /** * Make this view visible. If {@code false} is passed, the view will fade out it's content * and set the view Visibility to GONE. If only the content should be changed @@ -121,7 +128,7 @@ public abstract class StackScrollerDecorView extends ExpandableView { * @param nowVisible should the view be visible * @param animate should the change be animated. */ - public void setVisible(boolean nowVisible, boolean animate) { + public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) { if (mIsVisible != nowVisible) { mIsVisible = nowVisible; if (animate) { @@ -132,10 +139,10 @@ public abstract class StackScrollerDecorView extends ExpandableView { } else { setWillBeGone(true); } - setContentVisible(nowVisible, true /* animate */); + setContentVisible(nowVisible, true /* animate */, runAfter); } else { setVisibility(nowVisible ? VISIBLE : GONE); - setContentVisible(nowVisible, false /* animate */); + setContentVisible(nowVisible, false /* animate */, runAfter); setWillBeGone(false); notifyHeightChanged(false /* needsAnimation */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index 23aefd9bfd8e..594afceab63a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -46,6 +46,7 @@ public class NotificationRoundnessManager { private Runnable mRoundingChangedCallback; private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; + private boolean mIsDismissAllInProgress; private ExpandableView mSwipedView = null; private ExpandableView mViewBeforeSwipedView = null; @@ -162,6 +163,10 @@ public class NotificationRoundnessManager { } } + void setDismissAllInProgress(boolean isClearingAll) { + mIsDismissAllInProgress = isClearingAll; + } + private float getRoundness(ExpandableView view, boolean top) { if (view == null) { return 0f; @@ -171,6 +176,11 @@ public class NotificationRoundnessManager { || view == mViewAfterSwipedView) { return 1f; } + if (view instanceof ExpandableNotificationRow + && ((ExpandableNotificationRow) view).canViewBeDismissed() + && mIsDismissAllInProgress) { + return 1.0f; + } if ((view.isPinned() || (view.isHeadsUpAnimatingAway()) && !mExpanded)) { return 1.0f; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 0660daab3720..a771274e3433 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -144,6 +144,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean( "persist.debug.nssl.dismiss", false /* default */); + // Delay in milli-seconds before shade closes for clear all. + private final int DELAY_BEFORE_SHADE_CLOSE = 200; + private boolean mShadeNeedsToClose = false; + private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f; private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f; private static final float RUBBER_BAND_FACTOR_ON_PANEL_EXPAND = 0.21f; @@ -259,7 +263,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; - private boolean mFadeNotificationsOnDismiss; private FooterDismissListener mFooterDismissListener; private boolean mFlingAfterUpEvent; @@ -1192,7 +1195,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.COORDINATOR) private void clampScrollPosition() { int scrollRange = getScrollRange(); - if (scrollRange < mOwnScrollY) { + if (scrollRange < mOwnScrollY && !mAmbientState.isDismissAllInProgress()) { boolean animateStackY = false; if (scrollRange < getScrollAmountToScrollBoundary() && mAnimateStackYForContentHeightChange) { @@ -1708,6 +1711,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) { + if (child instanceof SectionHeaderView) { + ((StackScrollerDecorView) child).setContentVisible( + false /* visible */, true /* animate */, endRunnable); + return; + } mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration, true /* isDismissAll */); } @@ -4050,6 +4058,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable runAnimationFinishedRunnables(); clearTransient(); clearHeadsUpDisappearRunning(); + + if (mAmbientState.isDismissAllInProgress()) { + setDismissAllInProgress(false); + + if (mShadeNeedsToClose) { + mShadeNeedsToClose = false; + postDelayed( + () -> { + mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + }, + DELAY_BEFORE_SHADE_CLOSE /* delayMillis */); + } + } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -4407,6 +4428,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public void setDismissAllInProgress(boolean dismissAllInProgress) { mDismissAllInProgress = dismissAllInProgress; mAmbientState.setDismissAllInProgress(dismissAllInProgress); + mController.getNoticationRoundessManager().setDismissAllInProgress(dismissAllInProgress); handleDismissAllClipping(); } @@ -4947,129 +4969,137 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mHeadsUpAppearanceController = headsUpAppearanceController; } - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - @VisibleForTesting - void clearNotifications(@SelectedRows int selection, boolean closeShade) { - // animate-swipe all dismissable notifications, then animate the shade closed - int numChildren = getChildCount(); + private boolean isVisible(View child) { + boolean hasClipBounds = child.getClipBounds(mTmpRect); + return child.getVisibility() == View.VISIBLE + && (!hasClipBounds || mTmpRect.height() > 0); + } - final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); - final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); - for (int i = 0; i < numChildren; i++) { - final View child = getChildAt(i); - if (child instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) child; - boolean parentVisible = false; - boolean hasClipBounds = child.getClipBounds(mTmpRect); - if (includeChildInDismissAll(row, selection)) { - viewsToRemove.add(row); - if (child.getVisibility() == View.VISIBLE - && (!hasClipBounds || mTmpRect.height() > 0)) { - viewsToHide.add(child); - parentVisible = true; - } - } else if (child.getVisibility() == View.VISIBLE - && (!hasClipBounds || mTmpRect.height() > 0)) { - parentVisible = true; - } - List<ExpandableNotificationRow> children = row.getAttachedChildren(); - if (children != null) { - for (ExpandableNotificationRow childRow : children) { - if (includeChildInDismissAll(row, selection)) { - viewsToRemove.add(childRow); - if (parentVisible && row.areChildrenExpanded()) { - hasClipBounds = childRow.getClipBounds(mTmpRect); - if (childRow.getVisibility() == View.VISIBLE - && (!hasClipBounds || mTmpRect.height() > 0)) { - viewsToHide.add(childRow); - } - } - } - } - } + private boolean shouldHideParent(View view, @SelectedRows int selection) { + final boolean silentSectionWillBeGone = + !mController.hasNotifications(ROWS_GENTLE, false /* clearable */); + + // The only SectionHeaderView we have is the silent section header. + if (view instanceof SectionHeaderView && silentSectionWillBeGone) { + return true; + } + if (view instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) view; + if (isVisible(row) && includeChildInDismissAll(row, selection)) { + return true; } } + return false; + } - if (mDismissListener != null) { - mDismissListener.onDismiss(selection); - } + private boolean isChildrenVisible(ExpandableNotificationRow parent) { + List<ExpandableNotificationRow> children = parent.getAttachedChildren(); + return isVisible(parent) + && children != null + && parent.areChildrenExpanded(); + } + + // Similar to #getRowsToDismissInBackend, but filters for visible views. + private ArrayList<View> getVisibleViewsToAnimateAway(@SelectedRows int selection) { + final int viewCount = getChildCount(); + final ArrayList<View> viewsToHide = new ArrayList<>(viewCount); + + for (int i = 0; i < viewCount; i++) { + final View view = getChildAt(i); - if (viewsToRemove.isEmpty()) { - if (closeShade && mShadeController != null) { - mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); + if (shouldHideParent(view, selection)) { + viewsToHide.add(view); } - return; - } + if (view instanceof ExpandableNotificationRow) { + ExpandableNotificationRow parent = (ExpandableNotificationRow) view; - performDismissAllAnimations( - viewsToHide, - closeShade, - () -> onDismissAllAnimationsEnd(viewsToRemove, selection)); + if (isChildrenVisible(parent)) { + for (ExpandableNotificationRow child : parent.getAttachedChildren()) { + if (isVisible(child) && includeChildInDismissAll(child, selection)) { + viewsToHide.add(child); + } + } + } + } + } + return viewsToHide; } - private boolean includeChildInDismissAll( - ExpandableNotificationRow row, + private ArrayList<ExpandableNotificationRow> getRowsToDismissInBackend( @SelectedRows int selection) { - return canChildBeDismissed(row) && matchesSelection(row, selection); + final int childCount = getChildCount(); + final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(childCount); + + for (int i = 0; i < childCount; i++) { + final View view = getChildAt(i); + if (!(view instanceof ExpandableNotificationRow)) { + continue; + } + ExpandableNotificationRow parent = (ExpandableNotificationRow) view; + if (includeChildInDismissAll(parent, selection)) { + viewsToRemove.add(parent); + } + List<ExpandableNotificationRow> children = parent.getAttachedChildren(); + if (isVisible(parent) && children != null) { + for (ExpandableNotificationRow child : children) { + if (includeChildInDismissAll(parent, selection)) { + viewsToRemove.add(child); + } + } + } + } + return viewsToRemove; } /** - * Given a list of rows, animates them away in a staggered fashion as if they were dismissed. - * Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete - * handler. - * - * @param hideAnimatedList List of rows to animated away. Should only be views that are - * currently visible, or else the stagger will look funky. - * @param closeShade Whether to close the shade after the stagger animation completes. - * @param onAnimationComplete Called after the entire animation completes (including the shade - * closing if appropriate). The rows must be dismissed for real here. + * Collects a list of visible rows, and animates them away in a staggered fashion as if they + * were dismissed. Notifications are dismissed in the backend via onDismissAllAnimationsEnd. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private void performDismissAllAnimations( - final ArrayList<View> hideAnimatedList, - final boolean closeShade, - final Runnable onAnimationComplete) { - - final Runnable onSlideAwayAnimationComplete = () -> { - if (closeShade) { - mShadeController.addPostCollapseAction(() -> { - setDismissAllInProgress(false); - onAnimationComplete.run(); - }); - mShadeController.animateCollapsePanels( - CommandQueue.FLAG_EXCLUDE_NONE); - } else { - setDismissAllInProgress(false); - onAnimationComplete.run(); - } + @VisibleForTesting + void clearNotifications(@SelectedRows int selection, boolean closeShade) { + // Animate-swipe all dismissable notifications, then animate the shade closed + final ArrayList<View> viewsToAnimateAway = getVisibleViewsToAnimateAway(selection); + final ArrayList<ExpandableNotificationRow> rowsToDismissInBackend = + getRowsToDismissInBackend(selection); + if (mDismissListener != null) { + mDismissListener.onDismiss(selection); + } + final Runnable dismissInBackend = () -> { + onDismissAllAnimationsEnd(rowsToDismissInBackend, selection); }; - - if (hideAnimatedList.isEmpty()) { - onSlideAwayAnimationComplete.run(); + if (viewsToAnimateAway.isEmpty()) { + dismissInBackend.run(); return; } - - // let's disable our normal animations + // Disable normal animations setDismissAllInProgress(true); + mShadeNeedsToClose = closeShade; // Decrease the delay for every row we animate to give the sense of // accelerating the swipes - int rowDelayDecrement = 10; - int currentDelay = 140; - int totalDelay = 180; - int numItems = hideAnimatedList.size(); + final int rowDelayDecrement = 5; + int currentDelay = 60; + int totalDelay = 0; + final int numItems = viewsToAnimateAway.size(); for (int i = numItems - 1; i >= 0; i--) { - View view = hideAnimatedList.get(i); + View view = viewsToAnimateAway.get(i); Runnable endRunnable = null; if (i == 0) { - endRunnable = onSlideAwayAnimationComplete; + endRunnable = dismissInBackend; } dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE); - currentDelay = Math.max(50, currentDelay - rowDelayDecrement); + currentDelay = Math.max(30, currentDelay - rowDelayDecrement); totalDelay += currentDelay; } } + private boolean includeChildInDismissAll( + ExpandableNotificationRow row, + @SelectedRows int selection) { + return canChildBeDismissed(row) && matchesSelection(row, selection); + } + public void setNotificationActivityStarter( NotificationActivityStarter notificationActivityStarter) { mNotificationActivityStarter = notificationActivityStarter; @@ -5085,6 +5115,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mFooterDismissListener.onDismiss(); } clearNotifications(ROWS_ALL, true /* closeShade */); + footerView.setSecondaryVisible(false /* visible */, true /* animate */); }); footerView.setManageButtonClickListener(v -> { mNotificationActivityStarter.startHistoryIntent(v, mFooterView.isHistoryShown()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 9e4adce47e0c..faba48f82cb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1122,6 +1122,10 @@ public class NotificationStackScrollLayoutController { mZenModeController.areNotificationsHiddenInShade()); } + public boolean areNotificationsHiddenInShade() { + return mZenModeController.areNotificationsHiddenInShade(); + } + public boolean isShowingEmptyShadeView() { return mShowEmptyShadeView; } @@ -1170,6 +1174,10 @@ public class NotificationStackScrollLayoutController { * Return whether there are any clearable notifications */ public boolean hasActiveClearableNotifications(@SelectedRows int selection) { + return hasNotifications(selection, true /* clearable */); + } + + public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) { if (mDynamicPrivacyController.isInLockedDownShade()) { return false; } @@ -1180,8 +1188,11 @@ public class NotificationStackScrollLayoutController { continue; } final ExpandableNotificationRow row = (ExpandableNotificationRow) child; - if (row.canViewBeDismissed() && - NotificationStackScrollLayout.matchesSelection(row, selection)) { + final boolean matchClearable = + isClearable ? row.canViewBeDismissed() : !row.canViewBeDismissed(); + final boolean inSection = + NotificationStackScrollLayout.matchesSelection(row, selection); + if (matchClearable && inSection) { return true; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 2c810c93b2ee..8be5de7ae56e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -366,6 +366,20 @@ public class StackScrollAlgorithm { return stackHeight / stackEndHeight; } + public boolean hasOngoingNotifs(StackScrollAlgorithmState algorithmState) { + for (int i = 0; i < algorithmState.visibleChildren.size(); i++) { + View child = algorithmState.visibleChildren.get(i); + if (!(child instanceof ExpandableNotificationRow)) { + continue; + } + final ExpandableNotificationRow row = (ExpandableNotificationRow) child; + if (!row.canViewBeDismissed()) { + return true; + } + } + return false; + } + // TODO(b/172289889) polish shade open from HUN /** * Populates the {@link ExpandableViewState} for a single child. @@ -430,7 +444,9 @@ public class StackScrollAlgorithm { + view.getIntrinsicHeight(); final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight(); ((FooterView.FooterViewState) viewState).hideContent = - isShelfShowing || noSpaceForFooter; + isShelfShowing || noSpaceForFooter + || (ambientState.isDismissAllInProgress() + && !hasOngoingNotifs(algorithmState)); } } else { if (view != ambientState.getTrackedHeadsUpRow()) { @@ -467,7 +483,6 @@ public class StackScrollAlgorithm { } } } - // Clip height of view right before shelf. viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index ee12b4b2d728..4466cfe99fe1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -46,7 +46,7 @@ public class StackStateAnimator { public static final int ANIMATION_DURATION_WAKEUP = 500; public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448; public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464; - public static final int ANIMATION_DURATION_SWIPE = 260; + public static final int ANIMATION_DURATION_SWIPE = 200; public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220; public static final int ANIMATION_DURATION_CLOSE_REMOTE_INPUT = 150; public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 400; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 5a6db213d87f..36f6c4fd57a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -268,6 +268,13 @@ public class DozeParameters implements TunerService.Tunable, } /** + * Whether the brightness sensor uses the proximity sensor. + */ + public boolean brightnessUsesProx() { + return mResources.getBoolean(R.bool.doze_brightness_uses_prox); + } + + /** * Callback to listen for DozeParameter changes. */ public void addCallback(Callback callback) { @@ -303,6 +310,7 @@ public class DozeParameters implements TunerService.Tunable, pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold()); pw.print("getSelectivelyRegisterSensorsUsingProx(): "); pw.println(getSelectivelyRegisterSensorsUsingProx()); + pw.print("brightnessUsesProx(): "); pw.println(brightnessUsesProx()); } interface Callback { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 0a4e59c0391e..4701d8b32ee6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -203,13 +203,15 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private ControlsListingController.ControlsListingCallback mListingCallback = new ControlsListingController.ControlsListingCallback() { public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) { - boolean available = !serviceInfos.isEmpty(); + post(() -> { + boolean available = !serviceInfos.isEmpty(); - if (available != mControlServicesAvailable) { - mControlServicesAvailable = available; - updateControlsVisibility(); - updateAffordanceColors(); - } + if (available != mControlServicesAvailable) { + mControlServicesAvailable = available; + updateControlsVisibility(); + updateAffordanceColors(); + } + }); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index e272d2713e2a..55e0c9b979c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -96,7 +96,8 @@ public class KeyguardStatusBarView extends RelativeLayout implements private final UserManager mUserManager; private int mSystemIconsSwitcherHiddenExpandedMargin; - private int mSystemIconsBaseMargin; + private int mStatusBarPaddingEnd; + private int mMinDotWidth; private View mSystemIconsContainer; private TintedIconManager mIconManager; private List<String> mBlockedIcons = new ArrayList<>(); @@ -157,14 +158,7 @@ public class KeyguardStatusBarView extends RelativeLayout implements mMultiUserAvatar.setLayoutParams(lp); // System icons - lp = (MarginLayoutParams) mSystemIconsContainer.getLayoutParams(); - lp.setMarginStart(getResources().getDimensionPixelSize( - R.dimen.system_icons_super_container_margin_start)); - mSystemIconsContainer.setLayoutParams(lp); - mSystemIconsContainer.setPaddingRelative(mSystemIconsContainer.getPaddingStart(), - mSystemIconsContainer.getPaddingTop(), - getResources().getDimensionPixelSize(R.dimen.system_icons_keyguard_padding_end), - mSystemIconsContainer.getPaddingBottom()); + updateSystemIconsLayoutParams(); // Respect font size setting. mCarrierLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, @@ -194,8 +188,10 @@ public class KeyguardStatusBarView extends RelativeLayout implements Resources res = getResources(); mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize( R.dimen.system_icons_switcher_hidden_expanded_margin); - mSystemIconsBaseMargin = res.getDimensionPixelSize( - R.dimen.system_icons_super_container_avatarless_margin_end); + mStatusBarPaddingEnd = res.getDimensionPixelSize( + R.dimen.status_bar_padding_end); + mMinDotWidth = res.getDimensionPixelSize( + R.dimen.ongoing_appops_dot_min_padding); mCutoutSideNudge = getResources().getDimensionPixelSize( R.dimen.display_cutout_margin_consumption); mShowPercentAvailable = getContext().getResources().getBoolean( @@ -243,16 +239,24 @@ public class KeyguardStatusBarView extends RelativeLayout implements private void updateSystemIconsLayoutParams() { LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams(); - // If the avatar icon is gone, we need to have some end margin to display the system icons - // correctly. - int baseMarginEnd = mMultiUserAvatar.getVisibility() == View.GONE - ? mSystemIconsBaseMargin - : 0; + + int marginStart = getResources().getDimensionPixelSize( + R.dimen.system_icons_super_container_margin_start); + + // Use status_bar_padding_end to replace original + // system_icons_super_container_avatarless_margin_end to prevent different end alignment + // between PhoneStatusBarView and KeyguardStatusBarView + int baseMarginEnd = mStatusBarPaddingEnd; int marginEnd = mKeyguardUserSwitcherEnabled ? mSystemIconsSwitcherHiddenExpandedMargin : baseMarginEnd; - marginEnd = calculateMargin(marginEnd, mPadding.second); - if (marginEnd != lp.getMarginEnd()) { + + // Align PhoneStatusBar right margin/padding, only use + // 1. status bar layout: mPadding(consider round_corner + privacy dot) + // 2. icon container: R.dimen.status_bar_padding_end + + if (marginEnd != lp.getMarginEnd() || marginStart != lp.getMarginStart()) { + lp.setMarginStart(marginStart); lp.setMarginEnd(marginEnd); mSystemIconsContainer.setLayoutParams(lp); } @@ -287,7 +291,13 @@ public class KeyguardStatusBarView extends RelativeLayout implements mPadding = StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner( mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding); - setPadding(mPadding.first, waterfallTop, mPadding.second, 0); + + // consider privacy dot space + final int minLeft = isLayoutRtl() ? Math.max(mMinDotWidth, mPadding.first) : mPadding.first; + final int minRight = isLayoutRtl() ? mPadding.second : + Math.max(mMinDotWidth, mPadding.second); + + setPadding(minLeft, waterfallTop, minRight, 0); } private boolean updateLayoutParamsNoCutout() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 15e0716f8c49..e6bb30624f77 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -635,6 +635,7 @@ public class NotificationPanelViewController extends PanelViewController { private int mQsClipBottom; private boolean mQsVisible; private final ContentResolver mContentResolver; + private float mMinFraction; private final Executor mUiExecutor; private final SecureSettings mSecureSettings; @@ -1795,6 +1796,15 @@ public class NotificationPanelViewController extends PanelViewController { return !mQsTouchAboveFalsingThreshold; } + /** + * Percentage of panel expansion offset, caused by pulling down on a heads-up. + */ + @Override + public void setMinFraction(float minFraction) { + mMinFraction = minFraction; + mDepthController.setPanelPullDownMinFraction(mMinFraction); + } + private float computeQsExpansionFraction() { if (mQSAnimatingHiddenFromCollapsed) { // When hiding QS from collapsed state, the expansion can sometimes temporarily @@ -2309,6 +2319,12 @@ public class NotificationPanelViewController extends PanelViewController { } } top += mOverStretchAmount; + // Correction for instant expansion caused by HUN pull down/ + if (mMinFraction > 0f && mMinFraction < 1f) { + float realFraction = + (getExpandedFraction() - mMinFraction) / (1f - mMinFraction); + top *= MathUtils.saturate(realFraction / mMinFraction); + } bottom = getView().getBottom(); // notification bounds should take full screen width regardless of insets left = 0; @@ -3439,7 +3455,7 @@ public class NotificationPanelViewController extends PanelViewController { } public void setPanelScrimMinFraction(float minFraction) { - mBar.panelScrimMinFractionChanged(minFraction); + mBar.onPanelMinFractionChanged(minFraction); } public void clearNotificationEffects() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java index 246810a2d70b..c26782b017c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java @@ -605,12 +605,11 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } @Override - public void setLightRevealScrimAmount(float amount) { - boolean lightRevealScrimOpaque = amount == 0; - if (mCurrentState.mLightRevealScrimOpaque == lightRevealScrimOpaque) { + public void setLightRevealScrimOpaque(boolean opaque) { + if (mCurrentState.mLightRevealScrimOpaque == opaque) { return; } - mCurrentState.mLightRevealScrimOpaque = lightRevealScrimOpaque; + mCurrentState.mLightRevealScrimOpaque = opaque; apply(mCurrentState); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index b5d9bd67bd2d..e57e2005e3b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -311,6 +311,12 @@ public class NotificationShadeWindowViewController { // Capture all touch events in always-on. return true; } + + if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) { + // capture all touches if the alt auth bouncer is showing + return true; + } + boolean intercept = false; if (mNotificationPanelViewController.isFullyExpanded() && mDragDownHelper.isDragDownEnabled() @@ -338,6 +344,12 @@ public class NotificationShadeWindowViewController { if (mStatusBarStateController.isDozing()) { handled = !mService.isPulsing(); } + + if (mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()) { + // eat the touch + handled = true; + } + if ((mDragDownHelper.isDragDownEnabled() && !handled) || mDragDownHelper.isDraggingDown()) { // we still want to finish our drag down gesture when locking the screen diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index f1b6c7c3ad19..eca91a3f6fb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import static java.lang.Float.isNaN; +import android.annotation.CallSuper; import android.content.Context; import android.os.Bundle; import android.os.Parcelable; @@ -162,7 +163,13 @@ public abstract class PanelBar extends FrameLayout { return mPanel == null || mPanel.getView().dispatchTouchEvent(event); } - public abstract void panelScrimMinFractionChanged(float minFraction); + /** + * Percentage of panel expansion offset, caused by pulling down on a heads-up. + */ + @CallSuper + public void onPanelMinFractionChanged(float minFraction) { + mPanel.setMinFraction(minFraction); + } /** * @param frac the fraction from the expansion in [0, 1] diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 323a1128d3bb..99c0c13ad3d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -338,6 +338,13 @@ public abstract class PanelViewController { protected abstract float getOpeningHeight(); /** + * Minimum fraction from where expansion should start. This is set when pulling down on a + * heads-up notification. + * @param minFraction Fraction from 0 to 1. + */ + public abstract void setMinFraction(float minFraction); + + /** * @return whether the swiping direction is upwards and above a 45 degree angle compared to the * horizontal direction */ @@ -1211,10 +1218,14 @@ public abstract class PanelViewController { case MotionEvent.ACTION_MOVE: final float h = y - mInitialTouchY; addMovement(event); - if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown) { + final boolean openShadeWithoutHun = + mPanelClosedOnDown && !mCollapsedAndHeadsUpOnDown; + if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown + || openShadeWithoutHun) { float hAbs = Math.abs(h); float touchSlop = getTouchSlop(event); - if ((h < -touchSlop || (mAnimatingOnDown && hAbs > touchSlop)) + if ((h < -touchSlop + || ((openShadeWithoutHun || mAnimatingOnDown) && hAbs > touchSlop)) && hAbs > Math.abs(x - mInitialTouchX)) { cancelHeightAnimator(); startExpandMotion(x, y, true /* startTracking */, mExpandedHeight); @@ -1227,10 +1238,7 @@ public abstract class PanelViewController { mVelocityTracker.clear(); break; } - - // Finally, if none of the above cases applies, ensure that touches do not get handled - // by the contents of a panel that is not showing (a bit of a hack to avoid b/178277858) - return (mView.getVisibility() != View.VISIBLE); + return false; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index c300b11b9a34..2ca36b648b76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -269,10 +269,11 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void panelScrimMinFractionChanged(float minFraction) { + public void onPanelMinFractionChanged(float minFraction) { if (isNaN(minFraction)) { throw new IllegalArgumentException("minFraction cannot be NaN"); } + super.onPanelMinFractionChanged(minFraction); if (mMinFraction != minFraction) { mMinFraction = minFraction; updateScrimFraction(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 7d25aeef6f98..43ec6e6e87d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -587,6 +587,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump if (isNaN(expansionFraction)) { return; } + expansionFraction = Interpolators + .getNotificationScrimAlpha(expansionFraction, false /* notification */); boolean qsBottomVisible = qsPanelBottomY > 0; if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) { mQsExpansion = expansionFraction; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 2c0de629de8a..15b8c67fd4ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -279,15 +279,41 @@ public enum ScrimState { BUBBLE_EXPANDED { @Override public void prepare(ScrimState previousState) { + mBehindAlpha = mClipQsScrim ? 1 : 0; + mNotifAlpha = 0; + mFrontAlpha = 0; + + mAnimationDuration = mKeyguardFadingAway + ? mKeyguardFadingAwayDuration + : StatusBar.FADE_KEYGUARD_DURATION; + + mAnimateChange = !mLaunchingAffordanceWithPreview; + mFrontTint = Color.TRANSPARENT; - mBehindTint = Color.TRANSPARENT; + mBehindTint = Color.BLACK; mBubbleTint = Color.BLACK; + mBlankScreen = false; - mFrontAlpha = 0f; - mBehindAlpha = mDefaultScrimAlpha; + if (previousState == ScrimState.AOD) { + // Set all scrims black, before they fade transparent. + updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */); + updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */); + if (mScrimForBubble != null) { + updateScrimColor(mScrimForBubble, 1f /* alpha */, Color.BLACK /* tint */); + } + + // Scrims should still be black at the end of the transition. + mFrontTint = Color.BLACK; + mBehindTint = Color.BLACK; + mBubbleTint = Color.BLACK; + mBlankScreen = true; + } + + if (mClipQsScrim) { + updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK); + } mAnimationDuration = ScrimController.ANIMATION_DURATION; - mBlankScreen = false; } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 4705a362b669..d7a359e9b4d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1044,7 +1044,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShadeWindowViewController, mNotificationPanelViewController, mAmbientIndicationContainer); - mDozeParameters.addCallback(this::updateLightRevealScrimVisibility); + updateLightRevealScrimVisibility(); mConfigurationController.addCallback(this); @@ -1261,8 +1261,19 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront, scrimForBubble); mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim); - mLightRevealScrim.setRevealAmountListener( - mNotificationShadeWindowController::setLightRevealScrimAmount); + mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> { + Runnable updateOpaqueness = () -> { + mNotificationShadeWindowController.setLightRevealScrimOpaque( + mLightRevealScrim.isScrimOpaque()); + }; + if (opaque) { + // Delay making the view opaque for a frame, because it needs some time to render + // otherwise this can lead to a flicker where the scrim doesn't cover the screen + mLightRevealScrim.post(updateOpaqueness); + } else { + updateOpaqueness.run(); + } + }); mUnlockedScreenOffAnimationController.initialize(this, mLightRevealScrim); updateLightRevealScrimVisibility(); @@ -4956,11 +4967,5 @@ public class StatusBar extends SystemUI implements DemoMode, } mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha()); - if (mFeatureFlags.useNewLockscreenAnimations() - && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) { - mLightRevealScrim.setVisibility(View.VISIBLE); - } else { - mLightRevealScrim.setVisibility(View.GONE); - } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 8a7708aaa8c2..3653b95351b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -303,8 +303,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * Sets a new alt auth interceptor. */ public void setAlternateAuthInterceptor(@NonNull AlternateAuthInterceptor authInterceptor) { - mAlternateAuthInterceptor = authInterceptor; - resetAlternateAuth(false); + if (!Objects.equals(mAlternateAuthInterceptor, authInterceptor)) { + mAlternateAuthInterceptor = authInterceptor; + resetAlternateAuth(false); + } } private void registerListeners() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 47deb1f0084b..8821de077ec3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -310,17 +310,11 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, private void onNotificationRemoved(String key, StatusBarNotification old, int reason) { if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); - if (old != null) { - if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications() - && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) { - if (mStatusBarStateController.getState() == StatusBarState.SHADE - && reason != NotificationListenerService.REASON_CLICK) { - mCommandQueue.animateCollapsePanels(); - } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED + if (old != null && CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications() + && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded() + && mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED && !isCollapsing()) { - mStatusBarStateController.setState(StatusBarState.KEYGUARD); - } - } + mStatusBarStateController.setState(StatusBarState.KEYGUARD); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 6b52dca42eda..f8120a8a7029 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -5,20 +5,23 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context import android.content.res.Configuration +import android.database.ContentObserver import android.os.Handler +import android.provider.Settings +import com.android.systemui.statusbar.StatusBarState import android.view.View import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardViewMediator import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.statusbar.LightRevealScrim -import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.notification.AnimatableProperty import com.android.systemui.statusbar.notification.PropertyAnimator import com.android.systemui.statusbar.notification.stack.AnimationProperties import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.settings.GlobalSettings import javax.inject.Inject /** @@ -46,13 +49,16 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val statusBarStateControllerImpl: StatusBarStateControllerImpl, private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>, private val keyguardStateController: KeyguardStateController, - private val dozeParameters: dagger.Lazy<DozeParameters> + private val dozeParameters: dagger.Lazy<DozeParameters>, + private val globalSettings: GlobalSettings ) : WakefulnessLifecycle.Observer { private val handler = Handler() private lateinit var statusBar: StatusBar private lateinit var lightRevealScrim: LightRevealScrim + private var animatorDurationScale = 1f + private var shouldAnimateInKeyguard = false private var lightRevealAnimationPlaying = false private var aodUiAnimationPlaying = false @@ -79,6 +85,12 @@ class UnlockedScreenOffAnimationController @Inject constructor( }) } + val animatorDurationScaleObserver = object : ContentObserver(null) { + override fun onChange(selfChange: Boolean) { + updateAnimatorDurationScale() + } + } + fun initialize( statusBar: StatusBar, lightRevealScrim: LightRevealScrim @@ -86,14 +98,25 @@ class UnlockedScreenOffAnimationController @Inject constructor( this.lightRevealScrim = lightRevealScrim this.statusBar = statusBar + updateAnimatorDurationScale() + globalSettings.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE), + /* notify for descendants */ false, + animatorDurationScaleObserver) wakefulnessLifecycle.addObserver(this) } + fun updateAnimatorDurationScale() { + animatorDurationScale = + globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f) + } + /** * Animates in the provided keyguard view, ending in the same position that it will be in on * AOD. */ fun animateInKeyguard(keyguardView: View, after: Runnable) { + shouldAnimateInKeyguard = false keyguardView.alpha = 0f keyguardView.visibility = View.VISIBLE @@ -138,6 +161,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( // Waking up, so reset this flag. decidedToAnimateGoingToSleep = null + shouldAnimateInKeyguard = false lightRevealAnimator.cancel() handler.removeCallbacksAndMessages(null) } @@ -146,7 +170,6 @@ class UnlockedScreenOffAnimationController @Inject constructor( // Set this to false in onFinishedWakingUp rather than onStartedWakingUp so that other // observers (such as StatusBar) can ask us whether we were playing the screen off animation // and reset accordingly. - lightRevealAnimationPlaying = false aodUiAnimationPlaying = false // If we can't control the screen off animation, we shouldn't mess with the StatusBar's @@ -167,15 +190,15 @@ class UnlockedScreenOffAnimationController @Inject constructor( if (dozeParameters.get().shouldControlUnlockedScreenOff()) { decidedToAnimateGoingToSleep = true + shouldAnimateInKeyguard = true lightRevealAnimationPlaying = true lightRevealAnimator.start() - handler.postDelayed({ aodUiAnimationPlaying = true // Show AOD. That'll cause the KeyguardVisibilityHelper to call #animateInKeyguard. statusBar.notificationPanelViewController.showAodUi() - }, ANIMATE_IN_KEYGUARD_DELAY) + }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong()) } else { decidedToAnimateGoingToSleep = false } @@ -228,6 +251,10 @@ class UnlockedScreenOffAnimationController @Inject constructor( return lightRevealAnimationPlaying || aodUiAnimationPlaying } + fun shouldAnimateInKeyguard(): Boolean { + return shouldAnimateInKeyguard + } + /** * Whether the light reveal animation is playing. The second part of the screen off animation, * where AOD animates in, might still be playing if this returns false. @@ -235,4 +262,4 @@ class UnlockedScreenOffAnimationController @Inject constructor( fun isScreenOffLightRevealAnimationPlaying(): Boolean { return lightRevealAnimationPlaying } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java index ab58286859cc..6d6320e6962d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java @@ -40,6 +40,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.settings.UserTracker; +import com.android.wifitrackerlib.MergedCarrierEntry; import com.android.wifitrackerlib.WifiEntry; import com.android.wifitrackerlib.WifiPickerTracker; @@ -68,6 +69,7 @@ public class AccessPointControllerImpl private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>(); private final UserManager mUserManager; + private final UserTracker mUserTracker; private final Executor mMainExecutor; private @Nullable WifiPickerTracker mWifiPickerTracker; @@ -84,6 +86,7 @@ public class AccessPointControllerImpl WifiPickerTrackerFactory wifiPickerTrackerFactory ) { mUserManager = userManager; + mUserTracker = userTracker; mCurrentUser = userTracker.getUserId(); mMainExecutor = mainExecutor; mWifiPickerTrackerFactory = wifiPickerTrackerFactory; @@ -118,6 +121,11 @@ public class AccessPointControllerImpl new UserHandle(mCurrentUser)); } + public boolean canConfigMobileData() { + return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, + UserHandle.of(mCurrentUser)) && mUserTracker.getUserInfo().isAdmin(); + } + public void onUserSwitched(int newUserId) { mCurrentUser = newUserId; } @@ -157,6 +165,15 @@ public class AccessPointControllerImpl } @Override + public MergedCarrierEntry getMergedCarrierEntry() { + if (mWifiPickerTracker == null) { + fireAcccessPointsCallback(Collections.emptyList()); + return null; + } + return mWifiPickerTracker.getMergedCarrierEntry(); + } + + @Override public int getIcon(WifiEntry ap) { int level = ap.getLevel(); return ICONS[Math.max(0, level)]; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index ef2ca985858d..eeea699a0b74 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -23,6 +23,7 @@ import android.telephony.SubscriptionInfo; import com.android.settingslib.net.DataUsageController; import com.android.systemui.demomode.DemoMode; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.wifitrackerlib.MergedCarrierEntry; import com.android.wifitrackerlib.WifiEntry; import java.util.List; @@ -223,9 +224,11 @@ public interface NetworkController extends CallbackController<SignalCallback>, D void addAccessPointCallback(AccessPointCallback callback); void removeAccessPointCallback(AccessPointCallback callback); void scanForAccessPoints(); + MergedCarrierEntry getMergedCarrierEntry(); int getIcon(WifiEntry ap); boolean connect(WifiEntry ap); boolean canConfigWifi(); + boolean canConfigMobileData(); public interface AccessPointCallback { void onAccessPointsChanged(List<WifiEntry> accessPoints); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index c49de7ab0e5d..af0d41331c28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -68,9 +68,12 @@ import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.demomode.DemoMode; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; +import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; +import com.android.systemui.qs.tiles.dialog.InternetDialogUtil; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; @@ -191,6 +194,8 @@ public class NetworkControllerImpl extends BroadcastReceiver private boolean mUserSetup; private boolean mSimDetected; private boolean mForceCellularValidated; + private InternetDialogFactory mInternetDialogFactory; + private Handler mMainHandler; private ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @@ -221,7 +226,9 @@ public class NetworkControllerImpl extends BroadcastReceiver DemoModeController demoModeController, CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags, - DumpManager dumpManager) { + DumpManager dumpManager, + @Main Handler handler, + InternetDialogFactory internetDialogFactory) { this(context, connectivityManager, telephonyManager, telephonyListenerManager, @@ -242,6 +249,8 @@ public class NetworkControllerImpl extends BroadcastReceiver featureFlags, dumpManager); mReceiverHandler.post(mRegisterListeners); + mMainHandler = handler; + mInternetDialogFactory = internetDialogFactory; } @VisibleForTesting @@ -480,6 +489,9 @@ public class NetworkControllerImpl extends BroadcastReceiver filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + if (InternetDialogUtil.isProviderModelEnabled(mContext)) { + filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY); + } mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler); mListening = true; @@ -788,6 +800,10 @@ public class NetworkControllerImpl extends BroadcastReceiver mConfig = Config.readConfig(mContext); mReceiverHandler.post(this::handleConfigurationChanged); break; + case Settings.Panel.ACTION_INTERNET_CONNECTIVITY: + mMainHandler.post(() -> mInternetDialogFactory.create(true, + mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi())); + break; default: int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 84d7c05ddc14..5d7d4809dd57 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -77,7 +77,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto; -import com.android.internal.util.ContrastColorUtil; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -204,7 +203,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene final int stroke = colorized ? mContext.getResources().getDimensionPixelSize( R.dimen.remote_input_view_text_stroke) : 0; if (colorized) { - final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor); + final boolean dark = Notification.Builder.isColorDark(backgroundColor); final int foregroundColor = dark ? Color.WHITE : Color.BLACK; final int inverseColor = dark ? Color.BLACK : Color.WHITE; editBgColor = backgroundColor; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 41b1dd12639a..4e33529f3c36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -628,7 +628,7 @@ public class SmartReplyView extends ViewGroup { mCurrentBackgroundColor = backgroundColor; mCurrentColorized = colorized; - final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor); + final boolean dark = Notification.Builder.isColorDark(backgroundColor); mCurrentTextColor = ContrastColorUtil.ensureTextContrast( dark ? mDefaultTextColorDarkBg : mDefaultTextColor, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt new file mode 100644 index 000000000000..ae9d9ee445f2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy + +import android.content.Context +import android.text.StaticLayout +import android.util.AttributeSet +import android.widget.TextView +import com.android.systemui.R + +/** + * View for showing a date that can toggle between two different formats depending on size. + * + * If no pattern can fit, it will display empty. + * + * @see R.styleable.VariableDateView_longDatePattern + * @see R.styleable.VariableDateView_shortDatePattern + */ +class VariableDateView(context: Context, attrs: AttributeSet) : TextView(context, attrs) { + + val longerPattern: String + val shorterPattern: String + + init { + val a = context.theme.obtainStyledAttributes( + attrs, + R.styleable.VariableDateView, + 0, 0) + longerPattern = a.getString(R.styleable.VariableDateView_longDatePattern) + ?: context.getString(R.string.system_ui_date_pattern) + shorterPattern = a.getString(R.styleable.VariableDateView_shortDatePattern) + ?: context.getString(R.string.abbrev_month_day_no_year) + + a.recycle() + } + + /** + * Freeze the pattern switching + * + * Use during animations if the container will change its size but this view should not change + */ + var freezeSwitching = false + + private var onMeasureListener: OnMeasureListener? = null + + fun onAttach(listener: OnMeasureListener?) { + onMeasureListener = listener + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val availableWidth = MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingEnd + if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED && !freezeSwitching) { + onMeasureListener?.onMeasureAction(availableWidth) + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + + fun getDesiredWidthForText(text: CharSequence): Float { + return StaticLayout.getDesiredWidth(text, paint) + } + + interface OnMeasureListener { + fun onMeasureAction(availableWidth: Int) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt new file mode 100644 index 000000000000..99d84c4d0ced --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.icu.text.DateFormat +import android.icu.text.DisplayContext +import android.icu.util.Calendar +import android.os.Handler +import android.os.HandlerExecutor +import android.os.UserHandle +import android.text.TextUtils +import android.util.Log +import androidx.annotation.VisibleForTesting +import com.android.systemui.Dependency +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.util.ViewController +import com.android.systemui.util.time.SystemClock +import java.text.FieldPosition +import java.text.ParsePosition +import java.util.Date +import java.util.Locale +import javax.inject.Inject +import javax.inject.Named + +@VisibleForTesting +internal fun getTextForFormat(date: Date?, format: DateFormat): String { + return if (format === EMPTY_FORMAT) { // Check if same object + "" + } else format.format(date) +} + +@VisibleForTesting +internal fun getFormatFromPattern(pattern: String?): DateFormat { + if (TextUtils.equals(pattern, "")) { + return EMPTY_FORMAT + } + val l = Locale.getDefault() + val format = DateFormat.getInstanceForSkeleton(pattern, l) + format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE) + return format +} + +private val EMPTY_FORMAT: DateFormat = object : DateFormat() { + override fun format( + cal: Calendar, + toAppendTo: StringBuffer, + fieldPosition: FieldPosition + ): StringBuffer? { + return null + } + + override fun parse(text: String, cal: Calendar, pos: ParsePosition) {} +} + +private const val DEBUG = false +private const val TAG = "VariableDateViewController" + +class VariableDateViewController( + private val systemClock: SystemClock, + private val broadcastDispatcher: BroadcastDispatcher, + private val timeTickHandler: Handler, + view: VariableDateView +) : ViewController<VariableDateView>(view) { + + private var dateFormat: DateFormat? = null + private var datePattern = view.longerPattern + set(value) { + if (field == value) return + field = value + dateFormat = null + if (isAttachedToWindow) { + post(::updateClock) + } + } + private var lastWidth = Integer.MAX_VALUE + private var lastText = "" + private var currentTime = Date() + + // View class easy accessors + private val longerPattern: String + get() = mView.longerPattern + private val shorterPattern: String + get() = mView.shorterPattern + private fun post(block: () -> Unit) = mView.handler?.post(block) + + private val intentReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + // If the handler is null, it means we received a broadcast while the view has not + // finished being attached or in the process of being detached. + // In that case, do not post anything. + val handler = mView.handler ?: return + val action = intent.action + if ( + Intent.ACTION_TIME_TICK == action || + Intent.ACTION_TIME_CHANGED == action || + Intent.ACTION_TIMEZONE_CHANGED == action || + Intent.ACTION_LOCALE_CHANGED == action + ) { + if ( + Intent.ACTION_LOCALE_CHANGED == action || + Intent.ACTION_TIMEZONE_CHANGED == action + ) { + // need to get a fresh date format + handler.post { dateFormat = null } + } + handler.post(::updateClock) + } + } + } + + private val onMeasureListener = object : VariableDateView.OnMeasureListener { + override fun onMeasureAction(availableWidth: Int) { + if (availableWidth != lastWidth) { + // maybeChangeFormat will post if the pattern needs to change. + maybeChangeFormat(availableWidth) + lastWidth = availableWidth + } + } + } + + override fun onViewAttached() { + val filter = IntentFilter().apply { + addAction(Intent.ACTION_TIME_TICK) + addAction(Intent.ACTION_TIME_CHANGED) + addAction(Intent.ACTION_TIMEZONE_CHANGED) + addAction(Intent.ACTION_LOCALE_CHANGED) + } + + broadcastDispatcher.registerReceiver(intentReceiver, filter, + HandlerExecutor(timeTickHandler), UserHandle.SYSTEM) + + post(::updateClock) + mView.onAttach(onMeasureListener) + } + + override fun onViewDetached() { + dateFormat = null + mView.onAttach(null) + broadcastDispatcher.unregisterReceiver(intentReceiver) + } + + private fun updateClock() { + if (dateFormat == null) { + dateFormat = getFormatFromPattern(datePattern) + } + + currentTime.time = systemClock.currentTimeMillis() + + val text = getTextForFormat(currentTime, dateFormat!!) + if (text != lastText) { + mView.setText(text) + lastText = text + } + } + + private fun maybeChangeFormat(availableWidth: Int) { + if (mView.freezeSwitching || + availableWidth > lastWidth && datePattern == longerPattern || + availableWidth < lastWidth && datePattern == "" + ) { + // Nothing to do + return + } + if (DEBUG) Log.d(TAG, "Width changed. Maybe changing pattern") + // Start with longer pattern and see what fits + var text = getTextForFormat(currentTime, getFormatFromPattern(longerPattern)) + var length = mView.getDesiredWidthForText(text) + if (length <= availableWidth) { + changePattern(longerPattern) + return + } + + text = getTextForFormat(currentTime, getFormatFromPattern(shorterPattern)) + length = mView.getDesiredWidthForText(text) + if (length <= availableWidth) { + changePattern(shorterPattern) + return + } + + changePattern("") + } + + private fun changePattern(newPattern: String) { + if (newPattern.equals(datePattern)) return + if (DEBUG) Log.d(TAG, "Changing pattern to $newPattern") + datePattern = newPattern + } + + class Factory @Inject constructor( + private val systemClock: SystemClock, + private val broadcastDispatcher: BroadcastDispatcher, + @Named(Dependency.TIME_TICK_HANDLER_NAME) private val handler: Handler + ) { + fun create(view: VariableDateView): VariableDateViewController { + return VariableDateViewController( + systemClock, + broadcastDispatcher, + handler, + view + ) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java index c3b4fbe9a13d..fe0b97056024 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java @@ -132,14 +132,18 @@ public class ThemeOverlayApplier implements Dumpable { /* Target package for each overlay category. */ private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>(); private final OverlayManager mOverlayManager; - private final Executor mExecutor; + private final Executor mBgExecutor; + private final Executor mMainExecutor; private final String mLauncherPackage; private final String mThemePickerPackage; - public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor, + public ThemeOverlayApplier(OverlayManager overlayManager, + Executor bgExecutor, + Executor mainExecutor, String launcherPackage, String themePickerPackage, DumpManager dumpManager) { mOverlayManager = overlayManager; - mExecutor = executor; + mBgExecutor = bgExecutor; + mMainExecutor = mainExecutor; mLauncherPackage = launcherPackage; mThemePickerPackage = themePickerPackage; mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet( @@ -170,12 +174,13 @@ public class ThemeOverlayApplier implements Dumpable { * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that * affect sysui will also be applied to the system user. */ - void applyCurrentUserOverlays( + public void applyCurrentUserOverlays( Map<String, OverlayIdentifier> categoryToPackage, FabricatedOverlay[] pendingCreation, int currentUser, - Set<UserHandle> managedProfiles) { - mExecutor.execute(() -> { + Set<UserHandle> managedProfiles, + Runnable onOverlaysApplied) { + mBgExecutor.execute(() -> { // Disable all overlays that have not been specified in the user setting. final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES); @@ -221,6 +226,7 @@ public class ThemeOverlayApplier implements Dumpable { try { mOverlayManager.commit(transaction.build()); + mMainExecutor.execute(onOverlaysApplied); } catch (SecurityException | IllegalStateException e) { Log.e(TAG, "setEnabled failed", e); } diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 81999b534046..c3327dfc6d4e 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -521,17 +521,21 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { .map(key -> key + " -> " + categoryToPackage.get(key)).collect( Collectors.joining(", "))); } + Runnable overlaysAppliedRunnable = () -> onOverlaysApplied(); if (mNeedsOverlayCreation) { mNeedsOverlayCreation = false; mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] { mSecondaryOverlay, mNeutralOverlay - }, currentUser, managedProfiles); + }, currentUser, managedProfiles, overlaysAppliedRunnable); } else { mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser, - managedProfiles); + managedProfiles, overlaysAppliedRunnable); } } + protected void onOverlaysApplied() { + } + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mSystemColors=" + mCurrentColors); diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index 98b4209ede00..bfa50bcee270 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -36,6 +36,7 @@ import android.os.UserHandle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.TextView; @@ -63,6 +64,8 @@ public class UsbPermissionActivity extends AlertActivity public void onCreate(Bundle icicle) { super.onCreate(icicle); + getWindow().addPrivateFlags( + WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); Intent intent = getIntent(); mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java index 90e022a52d7a..bd1103982017 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java @@ -87,15 +87,23 @@ public class ProximitySensor implements ThresholdSensor { && (mLastPrimaryEvent == null || !mLastPrimaryEvent.getBelow() || !event.getBelow())) { - mSecondaryThresholdSensor.pause(); + chooseSensor(); if (mLastPrimaryEvent == null || !mLastPrimaryEvent.getBelow()) { // Only check the secondary as long as the primary thinks we're near. - mCancelSecondaryRunnable = null; + if (mCancelSecondaryRunnable != null) { + mCancelSecondaryRunnable.run(); + mCancelSecondaryRunnable = null; + } return; } else { // Check this sensor again in a moment. - mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed( - mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS); + mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(() -> { + // This is safe because we know that mSecondaryThresholdSensor + // is loaded, otherwise we wouldn't be here. + mPrimaryThresholdSensor.pause(); + mSecondaryThresholdSensor.resume(); + }, + SECONDARY_PING_INTERVAL_MS); } } logDebug("Secondary sensor event: " + event.getBelow() + "."); @@ -159,12 +167,8 @@ public class ProximitySensor implements ThresholdSensor { * of what is reported by the primary sensor. */ public void setSecondarySafe(boolean safe) { - mSecondarySafe = safe; - if (!mSecondarySafe) { - mSecondaryThresholdSensor.pause(); - } else { - mSecondaryThresholdSensor.resume(); - } + mSecondarySafe = mSecondaryThresholdSensor.isLoaded() && safe; + chooseSensor(); } /** @@ -209,16 +213,30 @@ public class ProximitySensor implements ThresholdSensor { return; } if (!mInitializedListeners) { + mPrimaryThresholdSensor.pause(); + mSecondaryThresholdSensor.pause(); mPrimaryThresholdSensor.register(mPrimaryEventListener); - if (!mSecondarySafe) { - mSecondaryThresholdSensor.pause(); - } mSecondaryThresholdSensor.register(mSecondaryEventListener); mInitializedListeners = true; } logDebug("Registering sensor listener"); - mPrimaryThresholdSensor.resume(); + mRegistered = true; + chooseSensor(); + } + + private void chooseSensor() { + mExecution.assertIsMainThread(); + if (!mRegistered || mPaused || mListeners.isEmpty()) { + return; + } + if (mSecondarySafe) { + mSecondaryThresholdSensor.resume(); + mPrimaryThresholdSensor.pause(); + } else { + mPrimaryThresholdSensor.resume(); + mSecondaryThresholdSensor.pause(); + } } /** @@ -312,7 +330,7 @@ public class ProximitySensor implements ThresholdSensor { } if (!mSecondarySafe && !event.getBelow()) { - mSecondaryThresholdSensor.pause(); + chooseSensor(); } mLastEvent = event; diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index f1c687ff3224..2c9c98032245 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -93,6 +93,13 @@ <activity android:name="com.android.systemui.screenshot.RecyclerViewActivity" android:exported="false" /> + <!-- started from UsbDeviceSettingsManager --> + <activity android:name=".usb.UsbPermissionActivityTest$UsbPermissionActivityTestable" + android:exported="false" + android:theme="@style/Theme.SystemUI.Dialog.Alert" + android:finishOnCloseSystemDialogs="true" + android:excludeFromRecents="true" /> + <provider android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer" tools:replace="android:authorities" diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 39d5314107ee..8dd5d6c01394 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -565,8 +565,9 @@ public class AuthControllerTest extends SysuiTestCase { credentialAllowed, true /* requireConfirmation */, 0 /* userId */, - "testPackage", 0 /* operationId */, + "testPackage", + 1 /* requestId */, BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT); } @@ -612,7 +613,7 @@ public class AuthControllerTest extends SysuiTestCase { @Override protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, - String opPackageName, boolean skipIntro, long operationId, + String opPackageName, boolean skipIntro, long operationId, long requestId, @BiometricManager.BiometricMultiSensorMode int multiSensorConfig) { mLastBiometricPromptInfo = promptInfo; diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 2120b0ee4790..cff2aed3f8fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.biometrics; +import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; + import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; @@ -69,6 +71,7 @@ import com.android.systemui.util.concurrency.Execution; import com.android.systemui.util.concurrency.FakeExecution; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; +import com.android.systemui.util.time.SystemClock; import org.junit.Before; import org.junit.Rule; @@ -147,6 +150,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private Handler mHandler; @Mock private ConfigurationController mConfigurationController; + @Mock + private SystemClock mSystemClock; private FakeExecutor mFgExecutor; @@ -229,7 +234,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mKeyguardBypassController, mDisplayManager, mHandler, - mConfigurationController); + mConfigurationController, + mSystemClock); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); @@ -413,6 +419,21 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test + public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException { + // GIVEN overlay was showing and the udfps bouncer is showing + mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); + when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true); + + // WHEN the overlay is hidden + mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); + mFgExecutor.runAllReady(); + + // THEN the udfps bouncer is reset + verify(mStatusBarKeyguardViewManager).resetAlternateAuth(eq(true)); + } + + @Test public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception { mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); @@ -544,5 +565,10 @@ public class UdfpsControllerTest extends SysuiTestCase { eq(mUdfpsController.EFFECT_CLICK), eq("udfps-onStart"), eq(UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES)); + + // THEN make sure vibration attributes has so that it always will play the haptic, + // even in battery saver mode + assertEquals(USAGE_ASSISTANCE_ACCESSIBILITY, + UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES.getUsage()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 5eb913856187..897ac270428f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -18,9 +18,9 @@ package com.android.systemui.biometrics; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeast; - import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -46,6 +46,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -89,6 +90,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { private ConfigurationController mConfigurationController; @Mock private UdfpsController mUdfpsController; + private FakeSystemClock mSystemClock = new FakeSystemClock(); private UdfpsKeyguardViewController mController; @@ -124,6 +126,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { mKeyguardViewMediator, mLockscreenShadeTransitionController, mConfigurationController, + mSystemClock, mKeyguardStateController, mUdfpsController); } @@ -299,6 +302,59 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { } @Test + public void testHiddenUdfpsBouncerOnTouchOutside_nothingHappens() { + // GIVEN view is attached + mController.onViewAttached(); + captureAltAuthInterceptor(); + + // GIVEN udfps bouncer isn't showing + mAltAuthInterceptor.hideAlternateAuthBouncer(); + + // WHEN touch is observed outside the view + mController.onTouchOutsideView(); + + // THEN bouncer / alt auth methods are never called + verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean()); + } + + @Test + public void testShowingUdfpsBouncerOnTouchOutsideWithinThreshold_nothingHappens() { + // GIVEN view is attached + mController.onViewAttached(); + captureAltAuthInterceptor(); + + // GIVEN udfps bouncer is showing + mAltAuthInterceptor.showAlternateAuthBouncer(); + + // WHEN touch is observed outside the view 200ms later (just within threshold) + mSystemClock.advanceTime(200); + mController.onTouchOutsideView(); + + // THEN bouncer / alt auth methods are never called because not enough time has passed + verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean()); + } + + @Test + public void testShowingUdfpsBouncerOnTouchOutsideAboveThreshold_showInputBouncer() { + // GIVEN view is attached + mController.onViewAttached(); + captureAltAuthInterceptor(); + + // GIVEN udfps bouncer is showing + mAltAuthInterceptor.showAlternateAuthBouncer(); + + // WHEN touch is observed outside the view 205ms later + mSystemClock.advanceTime(205); + mController.onTouchOutsideView(); + + // THEN show the bouncer and reset alt auth + verify(mStatusBarKeyguardViewManager).showBouncer(eq(true)); + verify(mStatusBarKeyguardViewManager).resetAlternateAuth(anyBoolean()); + } + + @Test public void testFadeInWithStatusBarExpansion() { // GIVEN view is attached mController.onViewAttached(); @@ -328,7 +384,41 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { // WHEN status bar expansion is 0 but udfps bouncer is requested mAltAuthInterceptor.showAlternateAuthBouncer(); - // THEN alpha is 0 + // THEN alpha is 255 + verify(mView).setUnpausedAlpha(255); + } + + @Test + public void testTransitionToFullShadeProgress() { + // GIVEN view is attached and status bar expansion is 1f + mController.onViewAttached(); + captureExpansionListeners(); + updateStatusBarExpansion(1f, true); + reset(mView); + + // WHEN we're transitioning to the full shade + float transitionProgress = .6f; + mController.setTransitionToFullShadeProgress(transitionProgress); + + // THEN alpha is between 0 and 255 + verify(mView).setUnpausedAlpha((int) ((1f - transitionProgress) * 255)); + } + + @Test + public void testShowUdfpsBouncer_transitionToFullShadeProgress() { + // GIVEN view is attached and status bar expansion is 1f + mController.onViewAttached(); + captureExpansionListeners(); + captureKeyguardStateControllerCallback(); + captureAltAuthInterceptor(); + updateStatusBarExpansion(1f, true); + mAltAuthInterceptor.showAlternateAuthBouncer(); + reset(mView); + + // WHEN we're transitioning to the full shade + mController.setTransitionToFullShadeProgress(1.0f); + + // THEN alpha is 255 (b/c udfps bouncer is requested) verify(mView).setUnpausedAlpha(255); } @@ -361,6 +451,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue(); } + + private void captureKeyguardStateControllerCallback() { verify(mKeyguardStateController).addCallback( mKeyguardStateControllerCallbackCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index d6226aa53f67..a32cb9b6baa9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -43,6 +43,7 @@ public class DozeConfigurationUtil { when(params.singleTapUsesProx()).thenReturn(true); when(params.longPressUsesProx()).thenReturn(true); when(params.getQuickPickupAodDuration()).thenReturn(500); + when(params.brightnessUsesProx()).thenReturn(true); doneHolder[0] = true; return params; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index 4e8b59c95681..deb7d31d87a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -29,6 +29,7 @@ import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -47,6 +48,7 @@ import android.view.Display; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.concurrency.FakeExecutor; @@ -82,6 +84,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { WakefulnessLifecycle mWakefulnessLifecycle; @Mock DozeParameters mDozeParameters; + @Mock + DockManager mDockManager; private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor); @@ -109,7 +113,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { mSensor = fakeSensorManager.getFakeLightSensor(); mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters); + mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); mScreen.onScreenState(Display.STATE_ON); } @@ -157,6 +161,67 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test + public void testAodDocked_doNotSelectivelyUseProx_usesLightSensor() { + // GIVEN the device doesn't need to selectively register for prox sensors and + // brightness sensor uses prox + when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false); + when(mDozeParameters.brightnessUsesProx()).thenReturn(true); + + // GIVEN the device is docked and the display state changes to ON + when(mDockManager.isDocked()).thenReturn(true); + mScreen.onScreenState(Display.STATE_ON); + waitForSensorManager(); + + // WHEN new sensor event sent + mSensor.sendSensorEvent(3); + + // THEN brightness is updated + assertEquals(3, mServiceFake.screenBrightness); + } + + @Test + public void testAodDocked_brightnessDoesNotUseProx_usesLightSensor() { + // GIVEN the device doesn't need to selectively register for prox sensors but + // the brightness sensor doesn't use prox + when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true); + when(mDozeParameters.brightnessUsesProx()).thenReturn(false); + + // GIVEN the device is docked and the display state changes to ON + when(mDockManager.isDocked()).thenReturn(true); + mScreen.onScreenState(Display.STATE_ON); + waitForSensorManager(); + + // WHEN new sensor event sent + mSensor.sendSensorEvent(3); + + // THEN brightness is updated + assertEquals(3, mServiceFake.screenBrightness); + } + + + @Test + public void testAodDocked_noProx_brightnessUsesProx_doNotUseLightSensor() { + final int startBrightness = mServiceFake.screenBrightness; + + // GIVEN the device needs to selectively register for prox sensors and + // the brightness sensor uses prox + when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true); + when(mDozeParameters.brightnessUsesProx()).thenReturn(true); + + // GIVEN the device is docked and the display state is on + when(mDockManager.isDocked()).thenReturn(true); + mScreen.onScreenState(Display.STATE_ON); + waitForSensorManager(); + + // WHEN new sensor event sent + mSensor.sendSensorEvent(3); + + // THEN brightness is NOT changed + assertNotSame(3, mServiceFake.screenBrightness); + assertEquals(startBrightness, mServiceFake.screenBrightness); + } + + @Test public void testPausingAod_doesNotResetBrightness() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); @@ -175,7 +240,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception { mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters); + mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); reset(mDozeHost); @@ -216,7 +281,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void testNullSensor() throws Exception { mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters); + mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 0c94f09c8572..5c4c27ccc4ca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -88,7 +88,7 @@ public class DozeSensorsTest extends SysuiTestCase { private FakeSettings mFakeSettings = new FakeSettings(); private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; private TestableLooper mTestableLooper; - private DozeSensors mDozeSensors; + private TestableDozeSensors mDozeSensors; private TriggerSensor mSensorTap; @Before @@ -170,6 +170,94 @@ public class DozeSensorsTest extends SysuiTestCase { assertTrue(mSensorTap.mRequested); } + @Test + public void testDozeSensorSetListening() { + // GIVEN doze sensors enabled + when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true); + + // GIVEN a trigger sensor + Sensor mockSensor = mock(Sensor.class); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + mockSensor, + /* settingEnabled */ true, + /* requiresTouchScreen */ true); + when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor))) + .thenReturn(true); + + // WHEN we want to listen for the trigger sensor + triggerSensor.setListening(true); + + // THEN the sensor is registered + assertTrue(triggerSensor.mRegistered); + } + + @Test + public void testDozeSensorSettingDisabled() { + // GIVEN doze sensors enabled + when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true); + + // GIVEN a trigger sensor + Sensor mockSensor = mock(Sensor.class); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + mockSensor, + /* settingEnabled*/ false, + /* requiresTouchScreen */ true); + when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor))) + .thenReturn(true); + + // WHEN setListening is called + triggerSensor.setListening(true); + + // THEN the sensor is not registered + assertFalse(triggerSensor.mRegistered); + } + + @Test + public void testDozeSensorIgnoreSetting() { + // GIVEN doze sensors enabled + when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true); + + // GIVEN a trigger sensor that's + Sensor mockSensor = mock(Sensor.class); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + mockSensor, + /* settingEnabled*/ false, + /* requiresTouchScreen */ true); + when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor))) + .thenReturn(true); + + // GIVEN sensor is listening + triggerSensor.setListening(true); + + // WHEN ignoreSetting is called + triggerSensor.ignoreSetting(true); + + // THEN the sensor is registered + assertTrue(triggerSensor.mRegistered); + } + + @Test + public void testUpdateListeningAfterAlreadyRegistered() { + // GIVEN doze sensors enabled + when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true); + + // GIVEN a trigger sensor + Sensor mockSensor = mock(Sensor.class); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + mockSensor, + /* settingEnabled*/ true, + /* requiresTouchScreen */ true); + when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor))) + .thenReturn(true); + + // WHEN setListening is called AND updateListening is called + triggerSensor.setListening(true); + triggerSensor.updateListening(); + + // THEN the sensor is still registered + assertTrue(triggerSensor.mRegistered); + } + private class TestableDozeSensors extends DozeSensors { TestableDozeSensors() { @@ -187,5 +275,17 @@ public class DozeSensorsTest extends SysuiTestCase { } mSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap}; } + + public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled, + boolean requiresTouchScreen) { + return new TriggerSensor(/* sensor */ sensor, + /* setting name */ "test_setting", + /* settingDefault */ settingEnabled, + /* configured */ true, + /* pulseReason*/ 0, + /* reportsTouchCoordinate*/ false, + requiresTouchScreen, + mDozeLog); + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java index 578c2d976cce..509ef82ee426 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -51,6 +52,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -112,6 +114,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { @Mock private Handler mHandler; @Mock private UserContextProvider mUserContextProvider; @Mock private StatusBar mStatusBar; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private TestableLooper mTestableLooper; @@ -156,7 +159,8 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { mSysUiState, mHandler, mPackageManager, - mStatusBar + mStatusBar, + mKeyguardUpdateMonitor ); mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting(); @@ -422,4 +426,31 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { restartAction.onLongPress(); verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_LONG_PRESS); } + + @Test + public void testOnLockScreen_disableSmartLock() { + mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite); + int user = KeyguardUpdateMonitor.getCurrentUser(); + doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems(); + doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); + doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); + doReturn(false).when(mStatusBar).isKeyguardShowing(); + String[] actions = { + GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + }; + doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); + + // When entering power menu from lockscreen, with smart lock enabled + when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true); + mGlobalActionsDialogLite.showOrHideDialog(true, true); + + // Then smart lock will be disabled + verify(mLockPatternUtils).requireCredentialEntry(eq(user)); + + // hide dialog again + mGlobalActionsDialogLite.showOrHideDialog(true, true); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index 2fa67cc0be60..338bb3037331 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -56,6 +56,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -126,6 +127,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase { @Mock private PackageManager mPackageManager; @Mock private SecureSettings mSecureSettings; @Mock private StatusBar mStatusBar; + @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private TestableLooper mTestableLooper; @@ -169,7 +171,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase { mSysUiState, mHandler, mPackageManager, - mStatusBar + mStatusBar, + mKeyguardUpdateMonitor ); mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index ad0878031679..31d70f5c811f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -67,7 +67,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) +@TestableLooper.RunWithLooper @SmallTest public class KeyguardViewMediatorTest extends SysuiTestCase { private KeyguardViewMediator mViewMediator; @@ -126,7 +126,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mUnlockedScreenOffAnimationController, () -> mNotificationShadeDepthController); mViewMediator.start(); - mViewMediator.onSystemReady(); } @Test @@ -165,8 +164,10 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { } @Test + @TestableLooper.RunWithLooper(setAsMainLooper = true) public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway() { // When showing and provisioned + mViewMediator.onSystemReady(); when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true); mViewMediator.setShowingLocked(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java new file mode 100644 index 000000000000..d279bbb02cee --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard; + +import static junit.framework.Assert.assertEquals; + +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.PointF; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.os.Vibrator; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.accessibility.AccessibilityManager; + +import androidx.test.filters.SmallTest; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardViewController; +import com.android.keyguard.LockIconView; +import com.android.keyguard.LockIconViewController; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; +import com.android.systemui.biometrics.AuthRippleController; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.concurrency.DelayableExecutor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class LockIconViewControllerTest extends SysuiTestCase { + private @Mock LockIconView mLockIconView; + private @Mock Context mContext; + private @Mock Resources mResources; + private @Mock DisplayMetrics mDisplayMetrics; + private @Mock StatusBarStateController mStatusBarStateController; + private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private @Mock KeyguardViewController mKeyguardViewController; + private @Mock KeyguardStateController mKeyguardStateController; + private @Mock FalsingManager mFalsingManager; + private @Mock AuthController mAuthController; + private @Mock DumpManager mDumpManager; + private @Mock AccessibilityManager mAccessibilityManager; + private @Mock ConfigurationController mConfigurationController; + private @Mock DelayableExecutor mDelayableExecutor; + private @Mock Vibrator mVibrator; + private @Mock AuthRippleController mAuthRippleController; + + private LockIconViewController mLockIconViewController; + + // Capture listeners so that they can be used to send events + @Captor private ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor = + ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); + private View.OnAttachStateChangeListener mAttachListener; + + @Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor; + private AuthController.Callback mAuthControllerCallback; + + @Captor private ArgumentCaptor<PointF> mPointCaptor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mLockIconView.getResources()).thenReturn(mResources); + when(mLockIconView.getContext()).thenReturn(mContext); + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); + + mLockIconViewController = new LockIconViewController( + mLockIconView, + mStatusBarStateController, + mKeyguardUpdateMonitor, + mKeyguardViewController, + mKeyguardStateController, + mFalsingManager, + mAuthController, + mDumpManager, + mAccessibilityManager, + mConfigurationController, + mDelayableExecutor, + mVibrator, + mAuthRippleController + ); + } + + @Test + public void testUpdateFingerprintLocationOnInit() { + // GIVEN fp sensor location is available pre-init + final PointF udfpsLocation = new PointF(50, 75); + final int radius = 33; + final FingerprintSensorPropertiesInternal fpProps = + new FingerprintSensorPropertiesInternal( + /* sensorId */ 0, + /* strength */ 0, + /* max enrollments per user */ 5, + /* component info */ new ArrayList<>(), + /* sensorType */ 3, + /* resetLockoutRequiresHwToken */ false, + (int) udfpsLocation.x, (int) udfpsLocation.y, radius); + when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation); + when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps)); + + // WHEN lock icon view controller is initialized and attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(null); + + // THEN lock icon view location is updated with the same coordinates as fpProps + verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius)); + assertEquals(udfpsLocation, mPointCaptor.getValue()); + } + + @Test + public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() { + // GIVEN fp sensor location is not available pre-init + when(mAuthController.getFingerprintSensorLocation()).thenReturn(null); + when(mAuthController.getUdfpsProps()).thenReturn(null); + mLockIconViewController.init(); + + // GIVEN fp sensor location is available post-init + captureAuthControllerCallback(); + final PointF udfpsLocation = new PointF(50, 75); + final int radius = 33; + final FingerprintSensorPropertiesInternal fpProps = + new FingerprintSensorPropertiesInternal( + /* sensorId */ 0, + /* strength */ 0, + /* max enrollments per user */ 5, + /* component info */ new ArrayList<>(), + /* sensorType */ 3, + /* resetLockoutRequiresHwToken */ false, + (int) udfpsLocation.x, (int) udfpsLocation.y, radius); + when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation); + when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps)); + + // WHEN all authenticators are registered + mAuthControllerCallback.onAllAuthenticatorsRegistered(); + + // THEN lock icon view location is updated with the same coordinates as fpProps + verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius)); + assertEquals(udfpsLocation, mPointCaptor.getValue()); + } + + private void captureAuthControllerCallback() { + verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture()); + mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue(); + } + + private void captureAttachListener() { + verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture()); + mAttachListener = mAttachCaptor.getValue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index b129fdd0d844..42629f545559 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -37,6 +37,7 @@ import android.widget.TextView import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.LiveData import androidx.test.filters.SmallTest +import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.media.dialog.MediaOutputDialogFactory import com.android.systemui.plugins.ActivityStarter @@ -101,7 +102,6 @@ public class MediaControlPanelTest : SysuiTestCase() { private lateinit var seamless: ViewGroup private lateinit var seamlessIcon: ImageView private lateinit var seamlessText: TextView - private lateinit var seamlessFallback: ImageView private lateinit var seekBar: SeekBar private lateinit var elapsedTimeView: TextView private lateinit var totalTimeView: TextView @@ -154,8 +154,6 @@ public class MediaControlPanelTest : SysuiTestCase() { whenever(holder.seamlessIcon).thenReturn(seamlessIcon) seamlessText = TextView(context) whenever(holder.seamlessText).thenReturn(seamlessText) - seamlessFallback = ImageView(context) - whenever(holder.seamlessFallback).thenReturn(seamlessFallback) seekBar = SeekBar(context) whenever(holder.seekBar).thenReturn(seekBar) elapsedTimeView = TextView(context) @@ -239,21 +237,19 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindDisabledDevice() { seamless.id = 1 - seamlessFallback.id = 2 + val fallbackString = context.getString(R.string.media_seamless_other_device) player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, true, null) player.bindPlayer(state, PACKAGE) - verify(expandedSet).setVisibility(seamless.id, View.GONE) - verify(expandedSet).setVisibility(seamlessFallback.id, View.VISIBLE) - verify(collapsedSet).setVisibility(seamless.id, View.GONE) - verify(collapsedSet).setVisibility(seamlessFallback.id, View.VISIBLE) + assertThat(seamless.isEnabled()).isFalse() + assertThat(seamlessText.getText()).isEqualTo(fallbackString) + assertThat(seamless.contentDescription).isEqualTo(fallbackString) } @Test fun bindNullDevice() { - val fallbackString = context.getResources().getString( - com.android.internal.R.string.ext_media_seamless_action) + val fallbackString = context.getResources().getString(R.string.media_seamless_other_device) player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index ba6dfd3c453a..5c3108c33147 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -163,7 +163,7 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test - fun testSetTimedOut_deactivatesMedia() { + fun testSetTimedOut_active_deactivatesMedia() { val data = MediaData(userId = USER_ID, initialized = true, backgroundColor = 0, app = null, appIcon = null, artist = null, song = null, artwork = null, actions = emptyList(), actionsToShowInCompact = emptyList(), packageName = "INVALID", token = null, @@ -176,6 +176,25 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test + fun testSetTimedOut_resume_dismissesMedia() { + // WHEN resume controls are present, and time out + val desc = MediaDescription.Builder().run { + setTitle(SESSION_TITLE) + build() + } + mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken, + APP_NAME, pendingIntent, PACKAGE_NAME) + backgroundExecutor.runAllReady() + foregroundExecutor.runAllReady() + mediaDataManager.setTimedOut(PACKAGE_NAME, timedOut = true) + + // THEN it is removed and listeners are informed + foregroundExecutor.advanceClockToLast() + foregroundExecutor.runAllReady() + verify(listener).onMediaDataRemoved(PACKAGE_NAME) + } + + @Test fun testLoadsMetadataOnBackground() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.numPending()).isEqualTo(1) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt index 150f4545bd43..359746bca0ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt @@ -91,10 +91,12 @@ class MediaResumeListenerTest : SysuiTestCase() { @Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback> @Captor lateinit var actionCaptor: ArgumentCaptor<Runnable> + @Captor lateinit var componentCaptor: ArgumentCaptor<String> private lateinit var executor: FakeExecutor private lateinit var data: MediaData private lateinit var resumeListener: MediaResumeListener + private val clock = FakeSystemClock() private var originalQsSetting = Settings.Global.getInt(context.contentResolver, Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1) @@ -122,9 +124,9 @@ class MediaResumeListenerTest : SysuiTestCase() { whenever(mockContext.packageManager).thenReturn(context.packageManager) whenever(mockContext.contentResolver).thenReturn(context.contentResolver) - executor = FakeExecutor(FakeSystemClock()) + executor = FakeExecutor(clock) resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor, - tunerService, resumeBrowserFactory, dumpManager) + tunerService, resumeBrowserFactory, dumpManager, clock) resumeListener.setManager(mediaDataManager) mediaDataManager.addListener(resumeListener) @@ -163,7 +165,7 @@ class MediaResumeListenerTest : SysuiTestCase() { // When listener is created, we do NOT register a user change listener val listener = MediaResumeListener(context, broadcastDispatcher, executor, tunerService, - resumeBrowserFactory, dumpManager) + resumeBrowserFactory, dumpManager, clock) listener.setManager(mediaDataManager) verify(broadcastDispatcher, never()).registerReceiver(eq(listener.userChangeReceiver), any(), any(), any()) @@ -328,4 +330,109 @@ class MediaResumeListenerTest : SysuiTestCase() { // Then we call restart verify(resumeBrowser).restart() } + + @Test + fun testOnUserUnlock_missingTime_saves() { + val currentTime = clock.currentTimeMillis() + + // When resume components without a last played time are loaded + testOnUserUnlock_loadsTracks() + + // Then we save an update with the current time + verify(sharedPrefsEditor).putString(any(), (capture(componentCaptor))) + componentCaptor.value.split(ResumeMediaBrowser.DELIMITER.toRegex()) + ?.dropLastWhile { it.isEmpty() }.forEach { + val result = it.split("/") + assertThat(result.size).isEqualTo(3) + assertThat(result[2].toLong()).isEqualTo(currentTime) + } + verify(sharedPrefsEditor, times(1)).apply() + } + + @Test + fun testLoadComponents_recentlyPlayed_adds() { + // Set up browser to return successfully + val description = MediaDescription.Builder().setTitle(TITLE).build() + val component = ComponentName(PACKAGE_NAME, CLASS_NAME) + whenever(resumeBrowser.token).thenReturn(token) + whenever(resumeBrowser.appIntent).thenReturn(pendingIntent) + whenever(resumeBrowser.findRecentMedia()).thenAnswer { + callbackCaptor.value.addTrack(description, component, resumeBrowser) + } + + // Set up shared preferences to have a component with a recent lastplayed time + val lastPlayed = clock.currentTimeMillis() + val componentsString = "$PACKAGE_NAME/$CLASS_NAME/$lastPlayed:" + whenever(sharedPrefs.getString(any(), any())).thenReturn(componentsString) + val resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor, + tunerService, resumeBrowserFactory, dumpManager, clock) + resumeListener.setManager(mediaDataManager) + mediaDataManager.addListener(resumeListener) + + // When we load a component that was played recently + val intent = Intent(Intent.ACTION_USER_UNLOCKED) + resumeListener.userChangeReceiver.onReceive(mockContext, intent) + + // We add its resume controls + verify(resumeBrowser, times(1)).findRecentMedia() + verify(mediaDataManager, times(1)).addResumptionControls(anyInt(), + any(), any(), any(), any(), any(), eq(PACKAGE_NAME)) + } + + @Test + fun testLoadComponents_old_ignores() { + // Set up shared preferences to have a component with an old lastplayed time + val lastPlayed = clock.currentTimeMillis() - RESUME_MEDIA_TIMEOUT - 100 + val componentsString = "$PACKAGE_NAME/$CLASS_NAME/$lastPlayed:" + whenever(sharedPrefs.getString(any(), any())).thenReturn(componentsString) + val resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor, + tunerService, resumeBrowserFactory, dumpManager, clock) + resumeListener.setManager(mediaDataManager) + mediaDataManager.addListener(resumeListener) + + // When we load a component that is not recent + val intent = Intent(Intent.ACTION_USER_UNLOCKED) + resumeListener.userChangeReceiver.onReceive(mockContext, intent) + + // We do not try to add resume controls + verify(resumeBrowser, times(0)).findRecentMedia() + verify(mediaDataManager, times(0)).addResumptionControls(anyInt(), + any(), any(), any(), any(), any(), any()) + } + + @Test + fun testOnLoad_hasService_updatesLastPlayed() { + // Set up browser to return successfully + val description = MediaDescription.Builder().setTitle(TITLE).build() + val component = ComponentName(PACKAGE_NAME, CLASS_NAME) + whenever(resumeBrowser.token).thenReturn(token) + whenever(resumeBrowser.appIntent).thenReturn(pendingIntent) + whenever(resumeBrowser.findRecentMedia()).thenAnswer { + callbackCaptor.value.addTrack(description, component, resumeBrowser) + } + + // Set up shared preferences to have a component with a lastplayed time + val currentTime = clock.currentTimeMillis() + val lastPlayed = currentTime - 1000 + val componentsString = "$PACKAGE_NAME/$CLASS_NAME/$lastPlayed:" + whenever(sharedPrefs.getString(any(), any())).thenReturn(componentsString) + val resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor, + tunerService, resumeBrowserFactory, dumpManager, clock) + resumeListener.setManager(mediaDataManager) + mediaDataManager.addListener(resumeListener) + + // When media data is loaded that has not been checked yet, and does have a MBS + val dataCopy = data.copy(resumeAction = null, hasCheckedForResume = false) + resumeListener.onMediaDataLoaded(KEY, null, dataCopy) + + // Then we store the new lastPlayed time + verify(sharedPrefsEditor).putString(any(), (capture(componentCaptor))) + componentCaptor.value.split(ResumeMediaBrowser.DELIMITER.toRegex()) + ?.dropLastWhile { it.isEmpty() }.forEach { + val result = it.split("/") + assertThat(result.size).isEqualTo(3) + assertThat(result[2].toLong()).isEqualTo(currentTime) + } + verify(sharedPrefsEditor, times(1)).apply() + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt index 0a573cd6020c..de2235dd1c42 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt @@ -71,6 +71,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { private lateinit var playbackBuilder: PlaybackState.Builder private lateinit var session: MediaSession private lateinit var mediaData: MediaData + private lateinit var resumeData: MediaData private lateinit var mediaTimeoutListener: MediaTimeoutListener @Before @@ -97,6 +98,10 @@ class MediaTimeoutListenerTest : SysuiTestCase() { mediaData = MediaData(USER_ID, true, 0, PACKAGE, null, null, SESSION_TITLE, null, emptyList(), emptyList(), PACKAGE, session.sessionToken, clickIntent = null, device = null, active = true, resumeAction = null) + + resumeData = MediaData(USER_ID, true, 0, PACKAGE, null, null, SESSION_TITLE, null, + emptyList(), emptyList(), PACKAGE, null, clickIntent = null, + device = null, active = false, resumeAction = null, resumption = true) } @Test @@ -120,6 +125,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { verify(mediaController).registerCallback(capture(mediaCallbackCaptor)) assertThat(executor.numPending()).isEqualTo(1) verify(timeoutCallback, never()).invoke(anyString(), anyBoolean()) + assertThat(executor.advanceClockToNext()).isEqualTo(PAUSED_MEDIA_TIMEOUT) } @Test @@ -188,6 +194,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder() .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()) assertThat(executor.numPending()).isEqualTo(1) + assertThat(executor.advanceClockToNext()).isEqualTo(PAUSED_MEDIA_TIMEOUT) } @Test @@ -229,7 +236,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { } @Test - fun testOnSessionDestroyed_clearsTimeout() { + fun testOnSessionDestroyed_active_clearsTimeout() { // GIVEN media that is paused val mediaPaused = mediaData.copy(isPlaying = false) mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaPaused) @@ -247,7 +254,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { @Test fun testSessionDestroyed_thenRestarts_resetsTimeout() { // Assuming we have previously destroyed the session - testOnSessionDestroyed_clearsTimeout() + testOnSessionDestroyed_active_clearsTimeout() // WHEN we get an update with media playing val playingState = mock(android.media.session.PlaybackState::class.java) @@ -264,4 +271,91 @@ class MediaTimeoutListenerTest : SysuiTestCase() { } verify(timeoutCallback).invoke(eq(KEY), eq(false)) } + + @Test + fun testOnSessionDestroyed_resume_continuesTimeout() { + // GIVEN resume media with session info + val resumeWithSession = resumeData.copy(token = session.sessionToken) + mediaTimeoutListener.onMediaDataLoaded(PACKAGE, null, resumeWithSession) + verify(mediaController).registerCallback(capture(mediaCallbackCaptor)) + assertThat(executor.numPending()).isEqualTo(1) + + // WHEN the session is destroyed + mediaCallbackCaptor.value.onSessionDestroyed() + + // THEN the controller is unregistered, but the timeout is still scheduled + verify(mediaController).unregisterCallback(anyObject()) + assertThat(executor.numPending()).isEqualTo(1) + } + + @Test + fun testOnMediaDataLoaded_activeToResume_registersTimeout() { + // WHEN a regular media is loaded + mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData) + + // AND it turns into a resume control + mediaTimeoutListener.onMediaDataLoaded(PACKAGE, KEY, resumeData) + + // THEN we register a timeout + assertThat(executor.numPending()).isEqualTo(1) + verify(timeoutCallback, never()).invoke(anyString(), anyBoolean()) + assertThat(executor.advanceClockToNext()).isEqualTo(RESUME_MEDIA_TIMEOUT) + } + + @Test + fun testOnMediaDataLoaded_pausedToResume_updatesTimeout() { + // WHEN regular media is paused + val pausedState = PlaybackState.Builder() + .setState(PlaybackState.STATE_PAUSED, 0L, 0f) + .build() + `when`(mediaController.playbackState).thenReturn(pausedState) + mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData) + assertThat(executor.numPending()).isEqualTo(1) + + // AND it turns into a resume control + mediaTimeoutListener.onMediaDataLoaded(PACKAGE, KEY, resumeData) + + // THEN we update the timeout length + assertThat(executor.numPending()).isEqualTo(1) + verify(timeoutCallback, never()).invoke(anyString(), anyBoolean()) + assertThat(executor.advanceClockToNext()).isEqualTo(RESUME_MEDIA_TIMEOUT) + } + + @Test + fun testOnMediaDataLoaded_resumption_registersTimeout() { + // WHEN a resume media is loaded + mediaTimeoutListener.onMediaDataLoaded(PACKAGE, null, resumeData) + + // THEN we register a timeout + assertThat(executor.numPending()).isEqualTo(1) + verify(timeoutCallback, never()).invoke(anyString(), anyBoolean()) + assertThat(executor.advanceClockToNext()).isEqualTo(RESUME_MEDIA_TIMEOUT) + } + + @Test + fun testOnMediaDataLoaded_resumeToActive_updatesTimeout() { + // WHEN we have a resume control + mediaTimeoutListener.onMediaDataLoaded(PACKAGE, null, resumeData) + + // AND that media is resumed + val playingState = PlaybackState.Builder() + .setState(PlaybackState.STATE_PAUSED, 0L, 0f) + .build() + `when`(mediaController.playbackState).thenReturn(playingState) + mediaTimeoutListener.onMediaDataLoaded(KEY, PACKAGE, mediaData) + + // THEN the timeout length is changed to a regular media control + assertThat(executor.advanceClockToNext()).isEqualTo(PAUSED_MEDIA_TIMEOUT) + } + + @Test + fun testOnMediaDataRemoved_resume_timeoutCancelled() { + // WHEN we have a resume control + testOnMediaDataLoaded_resumption_registersTimeout() + // AND the media is removed + mediaTimeoutListener.onMediaDataRemoved(PACKAGE) + + // THEN the timeout runnable is cancelled + assertThat(executor.numPending()).isEqualTo(0) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java index de7abf866f6a..922c6b648aab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java @@ -14,13 +14,19 @@ package com.android.systemui.qs; -import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION; import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER; -import static com.android.systemui.statusbar.phone.AutoTileManager.WORK; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.content.IntentFilter; import android.os.UserHandle; import android.provider.Settings.Secure; import android.testing.AndroidTestingRunner; @@ -28,13 +34,24 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; -import com.android.systemui.Prefs; -import com.android.systemui.Prefs.Key; import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.util.settings.FakeSettings; +import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.List; +import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -43,42 +60,38 @@ public class AutoAddTrackerTest extends SysuiTestCase { private static final int USER = 0; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; + @Mock + private QSHost mQSHost; + @Mock + private DumpManager mDumpManager; + @Captor + private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor; + @Captor + private ArgumentCaptor<IntentFilter> mIntentFilterArgumentCaptor; + + private Executor mBackgroundExecutor = Runnable::run; // Direct executor private AutoAddTracker mAutoTracker; + private SecureSettings mSecureSettings; @Before public void setUp() { - Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, ""); - } + MockitoAnnotations.initMocks(this); - @Test - public void testMigration() { - Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true); - Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true); - mAutoTracker = new AutoAddTracker(mContext, USER); - mAutoTracker.initialize(); + mSecureSettings = new FakeSettings(); - assertTrue(mAutoTracker.isAdded(SAVER)); - assertTrue(mAutoTracker.isAdded(WORK)); - assertFalse(mAutoTracker.isAdded(INVERSION)); + mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, null, USER); - // These keys have been removed; retrieving their values should always return the default. - assertTrue(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true )); - assertFalse(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, false)); - assertTrue(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, true)); - assertFalse(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, false)); - - mAutoTracker.destroy(); + mAutoTracker = createAutoAddTracker(USER); + mAutoTracker.initialize(); } @Test public void testChangeFromBackup() { - mAutoTracker = new AutoAddTracker(mContext, USER); - mAutoTracker.initialize(); - assertFalse(mAutoTracker.isAdded(SAVER)); - Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, SAVER); - mAutoTracker.mObserver.onChange(false); + mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, SAVER, USER); assertTrue(mAutoTracker.isAdded(SAVER)); @@ -87,9 +100,6 @@ public class AutoAddTrackerTest extends SysuiTestCase { @Test public void testSetAdded() { - mAutoTracker = new AutoAddTracker(mContext, USER); - mAutoTracker.initialize(); - assertFalse(mAutoTracker.isAdded(SAVER)); mAutoTracker.setTileAdded(SAVER); @@ -100,14 +110,12 @@ public class AutoAddTrackerTest extends SysuiTestCase { @Test public void testPersist() { - mAutoTracker = new AutoAddTracker(mContext, USER); - mAutoTracker.initialize(); - assertFalse(mAutoTracker.isAdded(SAVER)); mAutoTracker.setTileAdded(SAVER); mAutoTracker.destroy(); - mAutoTracker = new AutoAddTracker(mContext, USER); + mAutoTracker = createAutoAddTracker(USER); + mAutoTracker.initialize(); assertTrue(mAutoTracker.isAdded(SAVER)); @@ -116,22 +124,158 @@ public class AutoAddTrackerTest extends SysuiTestCase { @Test public void testIndependentUsers() { - mAutoTracker = new AutoAddTracker(mContext, USER); - mAutoTracker.initialize(); mAutoTracker.setTileAdded(SAVER); - mAutoTracker = new AutoAddTracker(mContext, USER + 1); + mAutoTracker = createAutoAddTracker(USER + 1); + mAutoTracker.initialize(); assertFalse(mAutoTracker.isAdded(SAVER)); } @Test public void testChangeUser() { - mAutoTracker = new AutoAddTracker(mContext, USER); - mAutoTracker.initialize(); mAutoTracker.setTileAdded(SAVER); - mAutoTracker = new AutoAddTracker(mContext, USER + 1); + mAutoTracker = createAutoAddTracker(USER + 1); mAutoTracker.changeUser(UserHandle.of(USER)); assertTrue(mAutoTracker.isAdded(SAVER)); } + + @Test + public void testBroadcastReceiverRegistered() { + verify(mBroadcastDispatcher).registerReceiver( + any(), mIntentFilterArgumentCaptor.capture(), any(), eq(UserHandle.of(USER))); + + assertTrue( + mIntentFilterArgumentCaptor.getValue().hasAction(Intent.ACTION_SETTING_RESTORED)); + } + + @Test + public void testBroadcastReceiverChangesWithUser() { + mAutoTracker.changeUser(UserHandle.of(USER + 1)); + + InOrder inOrder = Mockito.inOrder(mBroadcastDispatcher); + inOrder.verify(mBroadcastDispatcher).unregisterReceiver(any()); + inOrder.verify(mBroadcastDispatcher) + .registerReceiver(any(), any(), any(), eq(UserHandle.of(USER + 1))); + } + + @Test + public void testSettingRestoredWithTilesNotRemovedInSource_noAutoAddedInTarget() { + verify(mBroadcastDispatcher).registerReceiver( + mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any()); + + // These tiles were present in the original device + String restoredTiles = "saver,work,internet,cast"; + Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent); + + // And these tiles have been auto-added in the original device + // (no auto-added before restore) + String restoredAutoAddTiles = "work"; + Intent restoreAutoAddTilesIntent = + makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent); + + // Then, don't remove any current tiles + verify(mQSHost, never()).removeTiles(any()); + assertEquals(restoredAutoAddTiles, + mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER)); + } + + @Test + public void testSettingRestoredWithTilesRemovedInSource_noAutoAddedInTarget() { + verify(mBroadcastDispatcher) + .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any()); + + // These tiles were present in the original device + String restoredTiles = "saver,internet,cast"; + Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent); + + // And these tiles have been auto-added in the original device + // (no auto-added before restore) + String restoredAutoAddTiles = "work"; + Intent restoreAutoAddTilesIntent = + makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent); + + // Then, remove work tile + verify(mQSHost).removeTiles(List.of("work")); + assertEquals(restoredAutoAddTiles, + mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER)); + } + + @Test + public void testSettingRestoredWithTilesRemovedInSource_sameAutoAddedinTarget() { + verify(mBroadcastDispatcher) + .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any()); + + // These tiles were present in the original device + String restoredTiles = "saver,internet,cast"; + Intent restoreTilesIntent = + makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent); + + // And these tiles have been auto-added in the original device + // (no auto-added before restore) + String restoredAutoAddTiles = "work"; + Intent restoreAutoAddTilesIntent = + makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "work", restoredAutoAddTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent); + + // Then, remove work tile + verify(mQSHost).removeTiles(List.of("work")); + assertEquals(restoredAutoAddTiles, + mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER)); + } + + @Test + public void testSettingRestoredWithTilesRemovedInSource_othersAutoAddedinTarget() { + verify(mBroadcastDispatcher) + .registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any()); + + // These tiles were present in the original device + String restoredTiles = "saver,internet,cast"; + Intent restoreTilesIntent = + makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent); + + // And these tiles have been auto-added in the original device + // (no auto-added before restore) + String restoredAutoAddTiles = "work"; + Intent restoreAutoAddTilesIntent = + makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "inversion", restoredAutoAddTiles); + mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent); + + // Then, remove work tile + verify(mQSHost).removeTiles(List.of("work")); + + String setting = mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER); + assertEquals(2, setting.split(",").length); + assertTrue(setting.contains("work")); + assertTrue(setting.contains("inversion")); + } + + + private Intent makeRestoreIntent( + String settingName, String previousValue, String restoredValue) { + Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED); + intent.putExtra(Intent.EXTRA_SETTING_NAME, settingName); + intent.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, previousValue); + intent.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, restoredValue); + return intent; + } + + private AutoAddTracker createAutoAddTracker(int user) { + // Null handler wil dispatch sync. + return new AutoAddTracker( + mSecureSettings, + mBroadcastDispatcher, + mQSHost, + mDumpManager, + null, + mBackgroundExecutor, + user + ); + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 7f89b2629a6a..3ee3e55c749a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { () -> mock(AutoTileManager.class), mock(DumpManager.class), mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)), mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class), - mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags); + mock(SecureSettings.class), mock(CustomTileStatePersister.class)); qs.setHost(host); qs.setListening(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 4cbad5f15c5f..84bc12f6e922 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -18,14 +18,11 @@ package com.android.systemui.qs; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static junit.framework.TestCase.assertFalse; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -63,17 +60,16 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -121,12 +117,9 @@ public class QSTileHostTest extends SysuiTestCase { private UiEventLogger mUiEventLogger; @Mock private UserTracker mUserTracker; - @Mock private SecureSettings mSecureSettings; @Mock private CustomTileStatePersister mCustomTileStatePersister; - @Mock - private FeatureFlags mFeatureFlags; private Handler mHandler; private TestableLooper mLooper; @@ -137,14 +130,15 @@ public class QSTileHostTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mLooper = TestableLooper.get(this); mHandler = new Handler(mLooper.getLooper()); + + mSecureSettings = new FakeSettings(); + mSecureSettings.putStringForUser( + QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false); mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker, - mSecureSettings, mCustomTileStatePersister, mFeatureFlags); + mSecureSettings, mCustomTileStatePersister); setUpTileFactory(); - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); - when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt())) - .thenReturn(""); } private void setUpTileFactory() { @@ -172,13 +166,13 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpecs_emptySetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, ""); assertFalse(tiles.isEmpty()); } @Test public void testLoadTileSpecs_nullSetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, null); assertFalse(tiles.isEmpty()); } @@ -192,55 +186,6 @@ public class QSTileHostTest extends SysuiTestCase { } @Test - public void testRemoveWifiAndCellularWithoutInternet() { - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2"); - - assertEquals("internet", mQSTileHost.mTileSpecs.get(0)); - assertEquals("spec1", mQSTileHost.mTileSpecs.get(1)); - assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); - } - - @Test - public void testRemoveWifiAndCellularWithInternet() { - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet"); - - assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); - assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); - assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); - } - - @Test - public void testRemoveWifiWithoutInternet() { - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2"); - - assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); - assertEquals("internet", mQSTileHost.mTileSpecs.get(1)); - assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); - } - - @Test - public void testRemoveCellWithInternet() { - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet"); - - assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); - assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); - assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); - } - - @Test - public void testNoWifiNoCellularNoInternet() { - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); - - assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); - assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); - } - - @Test public void testSpecWithInvalidDoesNotUseDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); @@ -373,7 +318,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpec_repeated() { - List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2"); assertEquals(2, specs.size()); assertEquals("spec1", specs.get(0)); @@ -384,7 +329,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedInDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -395,7 +340,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedDefaultAndSetting() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -416,6 +361,16 @@ public class QSTileHostTest extends SysuiTestCase { .removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId())); } + @Test + public void testRemoveTiles() { + List<String> tiles = List.of("spec1", "spec2", "spec3"); + mQSTileHost.saveTilesToSettings(tiles); + + mQSTileHost.removeTiles(List.of("spec1", "spec2")); + + assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs); + } + private class TestQSTileHost extends QSTileHost { TestQSTileHost(Context context, StatusBarIconController iconController, QSFactory defaultFactory, Handler mainHandler, Looper bgLooper, @@ -423,12 +378,11 @@ public class QSTileHostTest extends SysuiTestCase { Provider<AutoTileManager> autoTiles, DumpManager dumpManager, BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, - SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, - FeatureFlags featureFlags) { + SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) { super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, tunerService, autoTiles, dumpManager, broadcastDispatcher, Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings, - customTileStatePersister, featureFlags); + customTileStatePersister); } @Override @@ -442,14 +396,11 @@ public class QSTileHostTest extends SysuiTestCase { @Override void saveTilesToSettings(List<String> tileSpecs) { super.saveTilesToSettings(tileSpecs); - - ArgumentCaptor<String> specs = ArgumentCaptor.forClass(String.class); - verify(mSecureSettings, atLeastOnce()).putStringForUser(eq(QSTileHost.TILES_SETTING), - specs.capture(), isNull(), eq(false), anyInt(), eq(true)); - // After tiles are changed, make sure to call onTuningChanged with the new setting if it // changed - onTuningChanged(TILES_SETTING, specs.getValue()); + String specs = mSecureSettings.getStringForUser( + QSTileHost.TILES_SETTING, mUserTracker.getUserId()); + onTuningChanged(TILES_SETTING, specs); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt index 35360bd19393..8b7e20ed0e5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt @@ -36,6 +36,8 @@ import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.policy.Clock +import com.android.systemui.statusbar.policy.VariableDateView +import com.android.systemui.statusbar.policy.VariableDateViewController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture @@ -87,8 +89,14 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { @Mock private lateinit var privacyDialogController: PrivacyDialogController @Mock + private lateinit var variableDateViewControllerFactory: VariableDateViewController.Factory + @Mock + private lateinit var variableDateViewController: VariableDateViewController + @Mock private lateinit var clock: Clock @Mock + private lateinit var variableDateView: VariableDateView + @Mock private lateinit var mockView: View @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var context: Context @@ -109,6 +117,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { stubViews() `when`(iconContainer.context).thenReturn(context) `when`(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController) + `when`(variableDateViewControllerFactory.create(any())) + .thenReturn(variableDateViewController) `when`(view.resources).thenReturn(mContext.resources) `when`(view.isAttachedToWindow).thenReturn(true) `when`(view.context).thenReturn(context) @@ -133,7 +143,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { colorExtractor, privacyDialogController, qsExpansionPathInterpolator, - featureFlags + featureFlags, + variableDateViewControllerFactory ) } @@ -274,6 +285,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { `when`(view.findViewById<StatusIconContainer>(R.id.statusIcons)).thenReturn(iconContainer) `when`(view.findViewById<OngoingPrivacyChip>(R.id.privacy_chip)).thenReturn(privacyChip) `when`(view.findViewById<Clock>(R.id.clock)).thenReturn(clock) + `when`(view.requireViewById<VariableDateView>(R.id.date)).thenReturn(variableDateView) + `when`(view.requireViewById<VariableDateView>(R.id.date_clock)).thenReturn(variableDateView) } private fun setPrivacyController(micCamera: Boolean, location: Boolean) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index c5b67091d197..4efcc5c3fc73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -58,7 +58,6 @@ import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -109,8 +108,6 @@ public class TileQueryHelperTest extends SysuiTestCase { private PackageManager mPackageManager; @Mock private UserTracker mUserTracker; - @Mock - private FeatureFlags mFeatureFlags; @Captor private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor; @@ -136,12 +133,12 @@ public class TileQueryHelperTest extends SysuiTestCase { } } ).when(mQSTileHost).createTile(anyString()); - when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); + FakeSystemClock clock = new FakeSystemClock(); mMainExecutor = new FakeExecutor(clock); mBgExecutor = new FakeExecutor(clock); mTileQueryHelper = new TileQueryHelper( - mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags); + mContext, mUserTracker, mMainExecutor, mBgExecutor); mTileQueryHelper.setListener(mListener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 01fa222896d3..2b1840462291 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -48,7 +48,6 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -99,8 +98,6 @@ public class TileServicesTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private SecureSettings mSecureSettings; - @Mock - private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { @@ -122,8 +119,7 @@ public class TileServicesTest extends SysuiTestCase { mUiEventLogger, mUserTracker, mSecureSettings, - mock(CustomTileStatePersister.class), - mFeatureFlags); + mock(CustomTileStatePersister.class)); mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher, mUserTracker); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java index 63ebe9290f64..23e51687f9e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -74,6 +75,24 @@ public class QSIconViewImplTest extends SysuiTestCase { } @Test + public void testMutateIconDrawable() { + SlashImageView iv = mock(SlashImageView.class); + Drawable originalDrawable = mock(Drawable.class); + Drawable otherDrawable = mock(Drawable.class); + State s = new State(); + s.icon = mock(Icon.class); + when(s.icon.getInvisibleDrawable(eq(mContext))).thenReturn(originalDrawable); + when(s.icon.getDrawable(eq(mContext))).thenReturn(originalDrawable); + when(iv.isShown()).thenReturn(true); + when(originalDrawable.getConstantState()).thenReturn(fakeConstantState(otherDrawable)); + + + mIconView.updateIcon(iv, s, /* allowAnimations= */true); + + verify(iv).setState(any(), eq(otherDrawable)); + } + + @Test public void testNoFirstFade() { ImageView iv = mock(ImageView.class); State s = new State(); @@ -104,4 +123,18 @@ public class QSIconViewImplTest extends SysuiTestCase { public void testIconNotSet_toString() { assertFalse(mIconView.toString().contains("lastIcon")); } + + private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) { + return new Drawable.ConstantState() { + @Override + public Drawable newDrawable() { + return otherDrawable; + } + + @Override + public int getChangingConfigurations() { + return 1; + } + }; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index d44a52607707..e939411e4a2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles; import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; @@ -327,4 +328,77 @@ public class CastTileTest extends SysuiTestCase { assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state); assertTrue(mCastTile.getState().secondaryLabel.toString().startsWith(connected.name)); } + + @Test + public void testExpandView_wifiNotConnected() { + mCastTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertFalse(mCastTile.getState().forceExpandIcon); + } + + @Test + public void testExpandView_wifiEnabledNotCasting() { + enableWifiAndProcessMessages(); + + assertTrue(mCastTile.getState().forceExpandIcon); + } + + @Test + public void testExpandView_casting_projection() { + CastController.CastDevice device = new CastController.CastDevice(); + device.state = CastController.CastDevice.STATE_CONNECTED; + List<CastDevice> devices = new ArrayList<>(); + devices.add(device); + when(mController.getCastDevices()).thenReturn(devices); + + enableWifiAndProcessMessages(); + + assertFalse(mCastTile.getState().forceExpandIcon); + } + + @Test + public void testExpandView_connecting_projection() { + CastController.CastDevice connecting = new CastController.CastDevice(); + connecting.state = CastDevice.STATE_CONNECTING; + connecting.name = "Test Casting Device"; + + List<CastDevice> devices = new ArrayList<>(); + devices.add(connecting); + when(mController.getCastDevices()).thenReturn(devices); + + enableWifiAndProcessMessages(); + + assertFalse(mCastTile.getState().forceExpandIcon); + } + + @Test + public void testExpandView_casting_mediaRoute() { + CastController.CastDevice device = new CastController.CastDevice(); + device.state = CastDevice.STATE_CONNECTED; + device.tag = mock(MediaRouter.RouteInfo.class); + List<CastDevice> devices = new ArrayList<>(); + devices.add(device); + when(mController.getCastDevices()).thenReturn(devices); + + enableWifiAndProcessMessages(); + + assertTrue(mCastTile.getState().forceExpandIcon); + } + + @Test + public void testExpandView_connecting_mediaRoute() { + CastController.CastDevice connecting = new CastController.CastDevice(); + connecting.state = CastDevice.STATE_CONNECTING; + connecting.tag = mock(RouteInfo.class); + connecting.name = "Test Casting Device"; + + List<CastDevice> devices = new ArrayList<>(); + devices.add(connecting); + when(mController.getCastDevices()).thenReturn(devices); + + enableWifiAndProcessMessages(); + + assertTrue(mCastTile.getState().forceExpandIcon); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java new file mode 100644 index 000000000000..77946cf791aa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java @@ -0,0 +1,167 @@ +package com.android.systemui.qs.tiles.dialog; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.graphics.drawable.Drawable; +import android.testing.AndroidTestingRunner; +import android.testing.TestableResources; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.test.filters.SmallTest; + +import com.android.settingslib.wifi.WifiUtils; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.wifitrackerlib.WifiEntry; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Arrays; +import java.util.List; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class InternetAdapterTest extends SysuiTestCase { + + private static final String WIFI_TITLE = "Wi-Fi Title"; + private static final String WIFI_SUMMARY = "Wi-Fi Summary"; + private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp; + private static final int LOCK_ICON_RES_ID = R.drawable.ic_friction_lock_closed; + + @Rule + public MockitoRule mRule = MockitoJUnit.rule(); + + @Mock + private WifiEntry mInternetWifiEntry; + @Mock + private List<WifiEntry> mWifiEntries; + @Mock + private WifiEntry mWifiEntry; + @Mock + private InternetDialogController mInternetDialogController; + @Mock + private WifiUtils.InternetIconInjector mWifiIconInjector; + @Mock + private Drawable mGearIcon; + @Mock + private Drawable mLockIcon; + + private TestableResources mTestableResources; + private InternetAdapter mInternetAdapter; + private InternetAdapter.InternetViewHolder mViewHolder; + + @Before + public void setUp() { + mTestableResources = mContext.getOrCreateTestableResources(); + when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE); + when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY); + when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true); + when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true); + when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE); + when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY); + + mInternetAdapter = new InternetAdapter(mInternetDialogController); + mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0); + mInternetAdapter.setWifiEntries(Arrays.asList(mWifiEntry), 1 /* wifiEntriesCount */); + mViewHolder.mWifiIconInjector = mWifiIconInjector; + } + + @Test + public void getItemCount_returnWifiEntriesCount() { + for (int i = 0; i < InternetDialogController.MAX_WIFI_ENTRY_COUNT; i++) { + mInternetAdapter.setWifiEntries(mWifiEntries, i /* wifiEntriesCount */); + + assertThat(mInternetAdapter.getItemCount()).isEqualTo(i); + } + } + + @Test + public void onBindViewHolder_bindWithOpenWifiNetwork_verifyView() { + when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_NONE); + mInternetAdapter.onBindViewHolder(mViewHolder, 0); + + assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void onBindViewHolder_bindWithSecurityWifiNetwork_verifyView() { + when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_PSK); + mInternetAdapter.onBindViewHolder(mViewHolder, 0); + + assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void onBindViewHolder_wifiLevelUnreachable_shouldNotGetWifiIcon() { + reset(mWifiIconInjector); + when(mWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE); + + mInternetAdapter.onBindViewHolder(mViewHolder, 0); + + verify(mWifiIconInjector, never()).getIcon(anyBoolean(), anyInt()); + } + + @Test + public void onBindViewHolder_shouldNotShowXLevelIcon_getIconWithInternet() { + when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(false); + + mInternetAdapter.onBindViewHolder(mViewHolder, 0); + + verify(mWifiIconInjector).getIcon(eq(false) /* noInternet */, anyInt()); + } + + @Test + public void onBindViewHolder_shouldShowXLevelIcon_getIconWithNoInternet() { + when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(true); + + mInternetAdapter.onBindViewHolder(mViewHolder, 0); + + verify(mWifiIconInjector).getIcon(eq(true) /* noInternet */, anyInt()); + } + + @Test + public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() { + mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon); + + mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_CONNECTED, WifiEntry.SECURITY_PSK); + + assertThat(mViewHolder.mWifiEndIcon.getDrawable()).isEqualTo(mGearIcon); + } + + @Test + public void viewHolderUpdateEndIcon_wifiDisconnectedAndSecurityPsk_updateLockIcon() { + mTestableResources.addOverride(LOCK_ICON_RES_ID, mLockIcon); + + mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_DISCONNECTED, WifiEntry.SECURITY_PSK); + + assertThat(mViewHolder.mWifiEndIcon.getDrawable()).isEqualTo(mLockIcon); + } + + @Test + public void viewHolderUpdateEndIcon_wifiDisconnectedAndSecurityNone_hideIcon() { + mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_DISCONNECTED, WifiEntry.SECURITY_NONE); + + assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.GONE); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java new file mode 100644 index 000000000000..baddacc3e6f5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java @@ -0,0 +1,485 @@ +package com.android.systemui.qs.tiles.dialog; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.text.TextUtils; + +import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.UiEventLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.settingslib.wifi.WifiUtils; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.time.FakeSystemClock; +import com.android.wifitrackerlib.WifiEntry; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class InternetDialogControllerTest extends SysuiTestCase { + + private static final int SUB_ID = 1; + private static final String CONNECTED_TITLE = "Connected Wi-Fi Title"; + private static final String CONNECTED_SUMMARY = "Connected Wi-Fi Summary"; + + @Mock + private WifiManager mWifiManager; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; + @Mock + private Handler mHandler; + @Mock + private ActivityStarter mActivityStarter; + @Mock + private GlobalSettings mGlobalSettings; + @Mock + private KeyguardStateController mKeyguardStateController; + @Mock + private NetworkController.AccessPointController mAccessPointController; + @Mock + private WifiEntry mConnectedEntry; + @Mock + private WifiEntry mWifiEntry1; + @Mock + private WifiEntry mWifiEntry2; + @Mock + private WifiEntry mWifiEntry3; + @Mock + private WifiEntry mWifiEntry4; + @Mock + private ServiceState mServiceState; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; + @Mock + private WifiUtils.InternetIconInjector mWifiIconInjector; + @Mock + InternetDialogController.InternetDialogCallback mInternetDialogCallback; + + private MockInternetDialogController mInternetDialogController; + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); + private List<WifiEntry> mAccessPoints = new ArrayList<>(); + private List<WifiEntry> mWifiEntries = new ArrayList<>(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt()); + when(mKeyguardStateController.isUnlocked()).thenReturn(true); + when(mConnectedEntry.isDefaultNetwork()).thenReturn(true); + when(mConnectedEntry.hasInternetAccess()).thenReturn(true); + when(mWifiEntry1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED); + when(mWifiEntry2.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED); + when(mWifiEntry3.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED); + when(mWifiEntry4.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED); + mAccessPoints.add(mConnectedEntry); + mAccessPoints.add(mWifiEntry1); + when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID}); + + mInternetDialogController = new MockInternetDialogController(mContext, + mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController, + mSubscriptionManager, mTelephonyManager, mWifiManager, + mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher, + mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController); + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, + mInternetDialogController.mOnSubscriptionsChangedListener); + mInternetDialogController.onStart(mInternetDialogCallback, true); + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + mInternetDialogController.mActivityStarter = mActivityStarter; + mInternetDialogController.mWifiIconInjector = mWifiIconInjector; + } + + @Test + public void getDialogTitleText_withAirplaneModeOn_returnAirplaneMode() { + mInternetDialogController.setAirplaneModeEnabled(true); + + assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(), + getResourcesString("airplane_mode"))); + } + + @Test + public void getDialogTitleText_withAirplaneModeOff_returnInternet() { + mInternetDialogController.setAirplaneModeEnabled(false); + + assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(), + getResourcesString("quick_settings_internet_label"))); + } + + @Test + public void getSubtitleText_withAirplaneModeOn_returnNull() { + mInternetDialogController.setAirplaneModeEnabled(true); + + assertThat(mInternetDialogController.getSubtitleText(false)).isNull(); + } + + @Test + public void getSubtitleText_withWifiOff_returnWifiIsOff() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(false); + + assertThat(mInternetDialogController.getSubtitleText(false)) + .isEqualTo(getResourcesString("wifi_is_off")); + + // if the Wi-Fi disallow config, then don't return Wi-Fi related string. + mInternetDialogController.mCanConfigWifi = false; + + assertThat(mInternetDialogController.getSubtitleText(false)) + .isNotEqualTo(getResourcesString("wifi_is_off")); + } + + @Test + public void getSubtitleText_withNoWifiEntry_returnSearchWifi() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + mInternetDialogController.onAccessPointsChanged(null /* accessPoints */); + + assertThat(mInternetDialogController.getSubtitleText(true)) + .isEqualTo(getResourcesString("wifi_empty_list_wifi_on")); + + // if the Wi-Fi disallow config, then don't return Wi-Fi related string. + mInternetDialogController.mCanConfigWifi = false; + + assertThat(mInternetDialogController.getSubtitleText(true)) + .isNotEqualTo(getResourcesString("wifi_empty_list_wifi_on")); + } + + @Test + public void getSubtitleText_withWifiEntry_returnTapToConnect() { + // The preconditions WiFi Entries is already in setUp() + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + + assertThat(mInternetDialogController.getSubtitleText(false)) + .isEqualTo(getResourcesString("tap_a_network_to_connect")); + + // if the Wi-Fi disallow config, then don't return Wi-Fi related string. + mInternetDialogController.mCanConfigWifi = false; + + assertThat(mInternetDialogController.getSubtitleText(false)) + .isNotEqualTo(getResourcesString("tap_a_network_to_connect")); + } + + @Test + public void getSubtitleText_deviceLockedWithWifiOn_returnUnlockToViewNetworks() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + when(mKeyguardStateController.isUnlocked()).thenReturn(false); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false), + getResourcesString("unlock_to_view_networks"))); + } + + @Test + public void getSubtitleText_withNoService_returnNoNetworksAvailable() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + mInternetDialogController.onAccessPointsChanged(null /* accessPoints */); + + doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState(); + doReturn(mServiceState).when(mTelephonyManager).getServiceState(); + doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState(); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false), + getResourcesString("all_network_unavailable"))); + } + + @Test + public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + mInternetDialogController.onAccessPointsChanged(null /* accessPoints */); + + doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); + doReturn(mServiceState).when(mTelephonyManager).getServiceState(); + + when(mTelephonyManager.isDataEnabled()).thenReturn(false); + + assertThat(mInternetDialogController.getSubtitleText(false)) + .isEqualTo(getResourcesString("non_carrier_network_unavailable")); + + // if the Wi-Fi disallow config, then don't return Wi-Fi related string. + mInternetDialogController.mCanConfigWifi = false; + + assertThat(mInternetDialogController.getSubtitleText(false)) + .isNotEqualTo(getResourcesString("non_carrier_network_unavailable")); + } + + @Test + public void getWifiDetailsSettingsIntent_withNoKey_returnNull() { + assertThat(mInternetDialogController.getWifiDetailsSettingsIntent(null)).isNull(); + } + + @Test + public void getWifiDetailsSettingsIntent_withKey_returnIntent() { + assertThat(mInternetDialogController.getWifiDetailsSettingsIntent("test_key")).isNotNull(); + } + + @Test + public void getInternetWifiDrawable_withConnectedEntry_returnIntentIconWithCorrectColor() { + final Drawable drawable = mock(Drawable.class); + when(mWifiIconInjector.getIcon(anyBoolean(), anyInt())).thenReturn(drawable); + + mInternetDialogController.getInternetWifiDrawable(mConnectedEntry); + + verify(mWifiIconInjector).getIcon(eq(false), anyInt()); + verify(drawable).setTint(mContext.getColor(R.color.connected_network_primary_color)); + } + + @Test + public void getInternetWifiDrawable_withWifiLevelUnreachable_returnNull() { + when(mConnectedEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE); + + Drawable drawable = mInternetDialogController.getInternetWifiDrawable(mConnectedEntry); + + assertThat(drawable).isNull(); + } + + @Test + public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() { + mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */); + + verify(mActivityStarter, never()) + .postStartActivityDismissingKeyguard(any(Intent.class), anyInt()); + } + + @Test + public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() { + mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key"); + + verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt()); + } + + @Test + public void isDeviceLocked_keyguardIsUnlocked_returnFalse() { + when(mKeyguardStateController.isUnlocked()).thenReturn(true); + + assertThat(mInternetDialogController.isDeviceLocked()).isFalse(); + } + + @Test + public void isDeviceLocked_keyguardIsLocked_returnTrue() { + when(mKeyguardStateController.isUnlocked()).thenReturn(false); + + assertThat(mInternetDialogController.isDeviceLocked()).isTrue(); + } + + @Test + public void onAccessPointsChanged_canNotConfigWifi_doNothing() { + reset(mInternetDialogCallback); + mInternetDialogController.mCanConfigWifi = false; + + mInternetDialogController.onAccessPointsChanged(null /* accessPoints */); + + verify(mInternetDialogCallback, never()).onAccessPointsChanged(any(), any()); + } + + @Test + public void onAccessPointsChanged_nullAccessPoints_callbackBothNull() { + reset(mInternetDialogCallback); + + mInternetDialogController.onAccessPointsChanged(null /* accessPoints */); + + verify(mInternetDialogCallback) + .onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */); + } + + @Test + public void onAccessPointsChanged_oneConnectedEntry_callbackConnectedEntryOnly() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mConnectedEntry); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + } + + @Test + public void onAccessPointsChanged_noConnectedEntryAndOneOther_callbackWifiEntriesOnly() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mWifiEntry1); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + mWifiEntries.add(mWifiEntry1); + verify(mInternetDialogCallback) + .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */); + } + + @Test + public void onAccessPointsChanged_oneConnectedEntryAndOneOther_callbackCorrectly() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mConnectedEntry); + mAccessPoints.add(mWifiEntry1); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + mWifiEntries.add(mWifiEntry1); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + } + + @Test + public void onAccessPointsChanged_oneConnectedEntryAndTwoOthers_callbackCorrectly() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mConnectedEntry); + mAccessPoints.add(mWifiEntry1); + mAccessPoints.add(mWifiEntry2); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + mWifiEntries.add(mWifiEntry1); + mWifiEntries.add(mWifiEntry2); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + } + + @Test + public void onAccessPointsChanged_oneConnectedEntryAndThreeOthers_callbackCutMore() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mConnectedEntry); + mAccessPoints.add(mWifiEntry1); + mAccessPoints.add(mWifiEntry2); + mAccessPoints.add(mWifiEntry3); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + mWifiEntries.add(mWifiEntry1); + mWifiEntries.add(mWifiEntry2); + mWifiEntries.add(mWifiEntry3); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + + // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one. + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(false); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.remove(mWifiEntry3); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + } + + @Test + public void onAccessPointsChanged_oneConnectedEntryAndFourOthers_callbackCutMore() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mConnectedEntry); + mAccessPoints.add(mWifiEntry1); + mAccessPoints.add(mWifiEntry2); + mAccessPoints.add(mWifiEntry3); + mAccessPoints.add(mWifiEntry4); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + mWifiEntries.add(mWifiEntry1); + mWifiEntries.add(mWifiEntry2); + mWifiEntries.add(mWifiEntry3); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + + // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one. + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(false); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.remove(mWifiEntry3); + verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); + } + + private String getResourcesString(String name) { + return mContext.getResources().getString(getResourcesId(name)); + } + + private int getResourcesId(String name) { + return mContext.getResources().getIdentifier(name, "string", + mContext.getPackageName()); + } + + private class MockInternetDialogController extends InternetDialogController { + + private GlobalSettings mGlobalSettings; + private boolean mIsAirplaneModeOn; + + MockInternetDialogController(Context context, UiEventLogger uiEventLogger, + ActivityStarter starter, AccessPointController accessPointController, + SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, + @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, + @Main Handler handler, @Main Executor mainExecutor, + BroadcastDispatcher broadcastDispatcher, + KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings, + KeyguardStateController keyguardStateController) { + super(context, uiEventLogger, starter, accessPointController, subscriptionManager, + telephonyManager, wifiManager, connectivityManager, handler, mainExecutor, + broadcastDispatcher, keyguardUpdateMonitor, globalSettings, + keyguardStateController); + mGlobalSettings = globalSettings; + } + + @Override + boolean isAirplaneModeEnabled() { + return mIsAirplaneModeOn; + } + + public void setAirplaneModeEnabled(boolean enabled) { + mIsAirplaneModeOn = enabled; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java new file mode 100644 index 000000000000..fa9c0538e9bd --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java @@ -0,0 +1,292 @@ +package com.android.systemui.qs.tiles.dialog; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.wifitrackerlib.WifiEntry; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class InternetDialogTest extends SysuiTestCase { + + private static final String MOBILE_NETWORK_TITLE = "Mobile Title"; + private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary"; + private static final String WIFI_TITLE = "Connected Wi-Fi Title"; + private static final String WIFI_SUMMARY = "Connected Wi-Fi Summary"; + + @Mock + private Handler mHandler; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private WifiManager mWifiManager; + @Mock + private WifiEntry mInternetWifiEntry; + @Mock + private List<WifiEntry> mWifiEntries; + @Mock + private InternetAdapter mInternetAdapter; + @Mock + private InternetDialogController mInternetDialogController; + + private InternetDialog mInternetDialog; + private View mDialogView; + private View mSubTitle; + private LinearLayout mMobileDataToggle; + private LinearLayout mWifiToggle; + private LinearLayout mConnectedWifi; + private RecyclerView mWifiList; + private LinearLayout mSeeAll; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt()); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE); + when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY); + when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true); + when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true); + when(mWifiEntries.size()).thenReturn(1); + + when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE); + when(mInternetDialogController.getMobileNetworkSummary()) + .thenReturn(MOBILE_NETWORK_SUMMARY); + when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager); + + mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class), + mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler); + mInternetDialog.mAdapter = mInternetAdapter; + mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry); + mInternetDialog.show(); + + mDialogView = mInternetDialog.mDialogView; + mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle); + mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout); + mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout); + mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout); + mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout); + mSeeAll = mDialogView.requireViewById(R.id.see_all_layout); + } + + @After + public void tearDown() { + mInternetDialog.dismissDialog(); + } + + @Test + public void hideWifiViews_WifiViewsGone() { + mInternetDialog.hideWifiViews(); + + assertThat(mInternetDialog.mIsProgressBarVisible).isFalse(); + assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE); + assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); + assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); + assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_withApmOn_internetDialogSubTitleGone() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_withApmOff_internetDialogSubTitleVisible() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); + + mInternetDialog.updateDialog(); + + assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void updateDialog_withApmOn_mobileDataLayoutGone() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() { + // The preconditions WiFi ON and Internet WiFi are already in setUp() + doReturn(false).when(mInternetDialogController).activeNetworkIsCellular(); + + mInternetDialog.updateDialog(); + + assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() { + // The precondition WiFi ON is already in setUp() + mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/); + doReturn(false).when(mInternetDialogController).activeNetworkIsCellular(); + + mInternetDialog.updateDialog(); + + assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOnAndNoWifiList_hideWifiListAndSeeAll() { + // The precondition WiFi ON is already in setUp() + mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry); + + mInternetDialog.updateDialog(); + + assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); + assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOnAndHasWifiList_showWifiListAndSeeAll() { + // The preconditions WiFi ON and WiFi entries are already in setUp() + + mInternetDialog.updateDialog(); + + assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void updateDialog_deviceLockedAndHasInternetWifi_showHighlightWifiToggle() { + // The preconditions WiFi ON and Internet WiFi are already in setUp() + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mWifiToggle.getBackground()).isNotNull(); + } + + @Test + public void updateDialog_deviceLockedAndHasInternetWifi_hideConnectedWifi() { + // The preconditions WiFi ON and Internet WiFi are already in setUp() + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_deviceLockedAndHasWifiList_hideWifiListAndSeeAll() { + // The preconditions WiFi entries are already in setUp() + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); + assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() { + mSeeAll.performClick(); + + verify(mInternetDialogController).launchNetworkSetting(); + } + + @Test + public void showProgressBar_wifiDisabled_hideProgressBar() { + Mockito.reset(mHandler); + when(mWifiManager.isWifiEnabled()).thenReturn(false); + + mInternetDialog.showProgressBar(); + + assertThat(mInternetDialog.mIsProgressBarVisible).isFalse(); + verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong()); + } + + @Test + public void showProgressBar_deviceLocked_hideProgressBar() { + Mockito.reset(mHandler); + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.showProgressBar(); + + assertThat(mInternetDialog.mIsProgressBarVisible).isFalse(); + verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong()); + } + + @Test + public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() { + Mockito.reset(mHandler); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + + mInternetDialog.showProgressBar(); + + // Show progress bar + assertThat(mInternetDialog.mIsProgressBarVisible).isTrue(); + + ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mHandler).postDelayed(runnableCaptor.capture(), + eq(InternetDialog.PROGRESS_DELAY_MS)); + runnableCaptor.getValue().run(); + + // Then hide progress bar + assertThat(mInternetDialog.mIsProgressBarVisible).isFalse(); + } + + @Test + public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() { + Mockito.reset(mHandler); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry*/); + + mInternetDialog.showProgressBar(); + + // Show progress bar + assertThat(mInternetDialog.mIsProgressBarVisible).isTrue(); + + ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mHandler).postDelayed(runnableCaptor.capture(), + eq(InternetDialog.PROGRESS_DELAY_MS)); + runnableCaptor.getValue().run(); + + // Then hide searching sub-title only + assertThat(mInternetDialog.mIsProgressBarVisible).isTrue(); + assertThat(mInternetDialog.mIsSearchingHidden).isTrue(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java index 10c878a92745..6f081c759df7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java @@ -34,6 +34,7 @@ import android.view.ScrollCaptureResponse; import androidx.test.filters.SmallTest; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; import com.android.systemui.screenshot.ScrollCaptureClient.Session; @@ -274,7 +275,8 @@ public class ScrollCaptureControllerTest extends SysuiTestCase { when(client.start(/* response */ any(), /* maxPages */ anyFloat())) .thenReturn(immediateFuture(session)); return new ScrollCaptureController(context, context.getMainExecutor(), - client, new ImageTileSet(context.getMainThreadHandler())); + client, new ImageTileSet(context.getMainThreadHandler()), + new UiEventLoggerFake()); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 21c6292c151f..f3762c566731 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -423,17 +423,18 @@ public class CommandQueueTest extends SysuiTestCase { final boolean credentialAllowed = true; final boolean requireConfirmation = true; final int userId = 10; - final String packageName = "test"; final long operationId = 1; + final String packageName = "test"; + final long requestId = 10; final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds, - credentialAllowed, requireConfirmation , userId, packageName, operationId, + credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId, multiSensorConfig); waitForIdleSync(); verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds), - eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName), - eq(operationId), eq(multiSensorConfig)); + eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId), + eq(packageName), eq(requestId), eq(multiSensorConfig)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index f5ce673c249e..09a3d35d2d32 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -111,6 +111,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo", "bar"); + private String mKeyguardTryFingerprintMsg; private String mDisclosureWithOrganization; private String mDisclosureGeneric; private String mFinancedDisclosureWithOrganization; @@ -182,6 +183,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mContext.addMockSystemService(UserManager.class, mUserManager); mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class)); mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class)); + mKeyguardTryFingerprintMsg = mContext.getString(R.string.keyguard_try_fingerprint); mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name, ORGANIZATION_NAME); mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic); @@ -637,7 +639,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { } @Test - public void onRefreshBatteryInfo_fullChargedWithOverheat_presentCharged() { + public void onRefreshBatteryInfo_fullChargedWithOverheat_presentChargingLimited() { createController(); BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING, 100 /* level */, BatteryManager.BATTERY_PLUGGED_AC, @@ -649,6 +651,24 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { verifyIndicationMessage( INDICATION_TYPE_BATTERY, + mContext.getString( + R.string.keyguard_plugged_in_charging_limited, + NumberFormat.getPercentInstance().format(100 / 100f))); + } + + @Test + public void onRefreshBatteryInfo_fullChargedWithoutOverheat_presentCharged() { + createController(); + BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING, + 100 /* level */, BatteryManager.BATTERY_PLUGGED_AC, + BatteryManager.BATTERY_HEALTH_GOOD, 0 /* maxChargingWattage */, + true /* present */); + + mController.getKeyguardCallback().onRefreshBatteryInfo(status); + mController.setVisible(true); + + verifyIndicationMessage( + INDICATION_TYPE_BATTERY, mContext.getString(R.string.keyguard_charged)); } @@ -677,6 +697,34 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { verifyTransientMessage(message); } + @Test + public void faceAuthMessageSuppressed() { + createController(); + String faceHelpMsg = "Face auth help message"; + + // GIVEN state of showing message when keyguard screen is on + when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); + when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true); + + // GIVEN fingerprint is also running (not udfps) + when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsAvailable()).thenReturn(false); + + mController.setVisible(true); + + // WHEN a face help message comes in + mController.getKeyguardCallback().onBiometricHelp( + KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, faceHelpMsg, + BiometricSourceType.FACE); + + // THEN "try fingerprint" message appears (and not the face help message) + verifyTransientMessage(mKeyguardTryFingerprintMsg); + + // THEN the face help message is still announced for a11y + verify(mIndicationAreaBottom).announceForAccessibility(eq(faceHelpMsg)); + } + private void sendUpdateDisclosureBroadcast() { mBroadcastReceiver.onReceive(mContext, new Intent()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt new file mode 100644 index 000000000000..97fe25d9a619 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar + +import android.testing.AndroidTestingRunner +import android.view.View +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import java.util.function.Consumer + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class LightRevealScrimTest : SysuiTestCase() { + + private lateinit var scrim: LightRevealScrim + private var isOpaque = false + + @Before + fun setUp() { + scrim = LightRevealScrim(context, null) + scrim.isScrimOpaqueChangedListener = Consumer { opaque -> + isOpaque = opaque + } + scrim.revealAmount = 0f + assertTrue("Scrim is not opaque in initial setup", scrim.isScrimOpaque) + } + + @Test + fun testAlphaSetsOpaque() { + scrim.alpha = 0.5f + assertFalse("Scrim is opaque even though alpha is set", scrim.isScrimOpaque) + } + + @Test + fun testVisibilitySetsOpaque() { + scrim.visibility = View.INVISIBLE + assertFalse("Scrim is opaque even though it's invisible", scrim.isScrimOpaque) + scrim.visibility = View.GONE + assertFalse("Scrim is opaque even though it's gone", scrim.isScrimOpaque) + } + + @Test + fun testRevealSetsOpaque() { + scrim.revealAmount = 0.5f + assertFalse("Scrim is opaque even though it's revealed", scrim.isScrimOpaque) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index a7b14460f925..465370b59553 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -25,6 +25,7 @@ import android.view.View import android.view.ViewRootImpl import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.Interpolators import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController @@ -32,6 +33,7 @@ import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.phone.ScrimController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.eq +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test @@ -167,6 +169,22 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { } @Test + fun onPanelExpansionChanged_respectsMinPanelPullDownFraction() { + notificationShadeDepthController.panelPullDownMinFraction = 0.5f + notificationShadeDepthController.onPanelExpansionChanged(0.5f /* expansion */, + true /* tracking */) + assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0f) + + notificationShadeDepthController.onPanelExpansionChanged(0.75f /* expansion */, + true /* tracking */) + assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0.5f) + + notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */, + true /* tracking */) + assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(1f) + } + + @Test fun onStateChanged_reevalutesBlurs_ifSameRadiusAndNewState() { onPanelExpansionChanged_apliesBlur_ifShade() clearInvocations(choreographer) @@ -178,10 +196,21 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { @Test fun setQsPanelExpansion_appliesBlur() { + statusBarState = StatusBarState.KEYGUARD notificationShadeDepthController.qsPanelExpansion = 1f - notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false) + notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false) notificationShadeDepthController.updateBlurCallback.doFrame(0) - verify(blurUtils).applyBlur(any(), anyInt(), eq(false)) + verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false)) + } + + @Test + fun setQsPanelExpansion_easing() { + statusBarState = StatusBarState.KEYGUARD + notificationShadeDepthController.qsPanelExpansion = 0.25f + notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false) + notificationShadeDepthController.updateBlurCallback.doFrame(0) + verify(wallpaperManager).setWallpaperZoomOut(any(), + eq(Interpolators.getNotificationScrimAlpha(0.25f, false /* notifications */))) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index 116f807a888d..efe6a31613e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -44,6 +44,8 @@ import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.FeatureFlags import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener import com.android.systemui.util.concurrency.FakeExecution import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any @@ -90,6 +92,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock + private lateinit var deviceProvisionedController: DeviceProvisionedController + @Mock private lateinit var handler: Handler @Mock @@ -107,12 +111,15 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { private lateinit var configChangeListenerCaptor: ArgumentCaptor<ConfigurationListener> @Captor private lateinit var statusBarStateListenerCaptor: ArgumentCaptor<StateListener> + @Captor + private lateinit var deviceProvisionedCaptor: ArgumentCaptor<DeviceProvisionedListener> private lateinit var sessionListener: OnTargetsAvailableListener private lateinit var userListener: UserTracker.Callback private lateinit var settingsObserver: ContentObserver private lateinit var configChangeListener: ConfigurationListener private lateinit var statusBarStateListener: StateListener + private lateinit var deviceProvisionedListener: DeviceProvisionedListener private val clock = FakeSystemClock() private val executor = FakeExecutor(clock) @@ -144,6 +151,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { `when`(plugin.getView(any())).thenReturn(fakeSmartspaceView) `when`(userTracker.userProfiles).thenReturn(userList) `when`(statusBarStateController.dozeAmount).thenReturn(0.5f) + `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true) + `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true) setActiveUser(userHandlePrimary) setAllowPrivateNotifications(userHandlePrimary, true) @@ -161,11 +170,15 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { contentResolver, configurationController, statusBarStateController, + deviceProvisionedController, execution, executor, handler, Optional.of(plugin) ) + + verify(deviceProvisionedController).addCallback(capture(deviceProvisionedCaptor)) + deviceProvisionedListener = deviceProvisionedCaptor.value } @Test(expected = RuntimeException::class) @@ -180,6 +193,27 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { } @Test + fun connectOnlyAfterDeviceIsProvisioned() { + // GIVEN an unprovisioned device and an attempt to connect + `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(false) + `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(false) + + // WHEN a connection attempt is made + controller.buildAndConnectView(fakeParent) + + // THEN no session is created + verify(smartspaceManager, never()).createSmartspaceSession(any()) + + // WHEN it does become provisioned + `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true) + `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true) + deviceProvisionedListener.onUserSetupChanged() + + // THEN the session is created + verify(smartspaceManager).createSmartspaceSession(any()) + } + + @Test fun testListenersAreRegistered() { // GIVEN a listener is added after a session is created connectSession() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index d7661be21752..f2477886eb68 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -141,7 +141,7 @@ import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -public class NotificationPanelViewTest extends SysuiTestCase { +public class NotificationPanelViewControllerTest extends SysuiTestCase { private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50; @@ -470,6 +470,12 @@ public class NotificationPanelViewTest extends SysuiTestCase { } @Test + public void testSetMinFraction() { + mNotificationPanelViewController.setMinFraction(0.5f); + verify(mNotificationShadeDepthController).setPanelPullDownMinFraction(eq(0.5f)); + } + + @Test public void testSetDozing_notifiesNsslAndStateController() { mNotificationPanelViewController.setDozing(true /* dozing */, false /* animate */, null /* touch */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java index ddd78541d113..90b8a74d88be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java @@ -146,7 +146,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { mNotificationShadeWindowController.attach(); clearInvocations(mWindowManager); - mNotificationShadeWindowController.setLightRevealScrimAmount(0f); + mNotificationShadeWindowController.setLightRevealScrimOpaque(true); verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture()); assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) == 0).isTrue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index 6c1a3c90d83d..bcc257dfa3d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -16,6 +16,11 @@ package com.android.systemui.statusbar.phone; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -55,6 +60,8 @@ import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -91,6 +98,10 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController; + @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler> + mInteractionEventHandlerCaptor; + private NotificationShadeWindowView.InteractionEventHandler mInteractionEventHandler; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -147,4 +158,49 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { verify(mDragDownHelper).onTouchEvent(ev); ev.recycle(); } + + @Test + public void testInterceptTouchWhenShowingAltAuth() { + captureInteractionEventHandler(); + + // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept + when(mStatusBarStateController.isDozing()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true); + when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); + + // THEN we should intercept touch + assertTrue(mInteractionEventHandler.shouldInterceptTouchEvent(mock(MotionEvent.class))); + } + + @Test + public void testNoInterceptTouch() { + captureInteractionEventHandler(); + + // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept + when(mStatusBarStateController.isDozing()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(false); + when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); + + // THEN we shouldn't intercept touch + assertFalse(mInteractionEventHandler.shouldInterceptTouchEvent(mock(MotionEvent.class))); + } + + @Test + public void testHandleTouchEventWhenShowingAltAuth() { + captureInteractionEventHandler(); + + // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept + when(mStatusBarStateController.isDozing()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()).thenReturn(true); + when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); + + // THEN we should handle the touch + assertTrue(mInteractionEventHandler.handleTouchEvent(mock(MotionEvent.class))); + } + + private void captureInteractionEventHandler() { + verify(mView).setInteractionEventHandler(mInteractionEventHandlerCaptor.capture()); + mInteractionEventHandler = mInteractionEventHandlerCaptor.getValue(); + + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 6de58667fb01..47c8806be6d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -624,7 +624,7 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimTinted(Map.of( mScrimInFront, false, - mScrimBehind, false, + mScrimBehind, true, mScrimForBubble, true )); @@ -705,7 +705,7 @@ public class ScrimControllerTest extends SysuiTestCase { public void qsExpansion_half_clippingQs() { reset(mScrimBehind); mScrimController.setClipsQsScrim(true); - mScrimController.setQsPosition(0.5f, 999 /* value doesn't matter */); + mScrimController.setQsPosition(0.25f, 999 /* value doesn't matter */); finishAnimationsImmediately(); assertScrimAlpha(Map.of( @@ -1136,7 +1136,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testScrimsVisible_whenShadeVisibleOnLockscreen() { mScrimController.transitionTo(ScrimState.KEYGUARD); - mScrimController.setQsPosition(0.5f, 300); + mScrimController.setQsPosition(0.25f, 300); assertScrimAlpha(Map.of( mScrimBehind, SEMI_TRANSPARENT, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 57198dbe18bb..4a5770d12239 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -238,7 +238,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { mNetworkController.setNoNetworksAvailable(false); setWifiStateForVcn(true, testSsid); setWifiLevelForVcn(0); - verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); + verifyLastMobileDataIndicatorsForVcn(true, 0, TelephonyIcons.ICON_CWF, false); mNetworkController.setNoNetworksAvailable(true); for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { @@ -246,11 +246,11 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { setConnectivityViaCallbackInNetworkControllerForVcn( NetworkCapabilities.TRANSPORT_CELLULAR, true, true, mVcnTransportInfo); - verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); + verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, true); setConnectivityViaCallbackInNetworkControllerForVcn( NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); - verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]); + verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt new file mode 100644 index 000000000000..871a48c503be --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy + +import android.os.Handler +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.anyString +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import java.util.Date + +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +@SmallTest +class VariableDateViewControllerTest : SysuiTestCase() { + + companion object { + private const val TIME_STAMP = 1_500_000_000_000 + private const val LONG_PATTERN = "EEEMMMd" + private const val SHORT_PATTERN = "MMMd" + private const val CHAR_WIDTH = 10f + } + + @Mock + private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock + private lateinit var view: VariableDateView + @Captor + private lateinit var onMeasureListenerCaptor: ArgumentCaptor<VariableDateView.OnMeasureListener> + + private var lastText: String? = null + + private lateinit var systemClock: FakeSystemClock + private lateinit var testableLooper: TestableLooper + private lateinit var testableHandler: Handler + private lateinit var controller: VariableDateViewController + + private lateinit var longText: String + private lateinit var shortText: String + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + testableHandler = Handler(testableLooper.looper) + + systemClock = FakeSystemClock() + systemClock.setCurrentTimeMillis(TIME_STAMP) + + `when`(view.longerPattern).thenReturn(LONG_PATTERN) + `when`(view.shorterPattern).thenReturn(SHORT_PATTERN) + `when`(view.handler).thenReturn(testableHandler) + + `when`(view.setText(anyString())).thenAnswer { + lastText = it.arguments[0] as? String + Unit + } + `when`(view.isAttachedToWindow).thenReturn(true) + + val date = Date(TIME_STAMP) + longText = getTextForFormat(date, getFormatFromPattern(LONG_PATTERN)) + shortText = getTextForFormat(date, getFormatFromPattern(SHORT_PATTERN)) + + // Assume some sizes for the text, the controller doesn't need to know if these sizes are + // the true ones + `when`(view.getDesiredWidthForText(any())).thenAnswer { + getTextLength(it.arguments[0] as CharSequence) + } + + controller = VariableDateViewController( + systemClock, + broadcastDispatcher, + testableHandler, + view + ) + + controller.init() + testableLooper.processAllMessages() + + verify(view).onAttach(capture(onMeasureListenerCaptor)) + } + + @Test + fun testViewStartsWithLongText() { + assertThat(lastText).isEqualTo(longText) + } + + @Test + fun testListenerNotNull() { + assertThat(onMeasureListenerCaptor.value).isNotNull() + } + + @Test + fun testLotsOfSpaceUseLongText() { + onMeasureListenerCaptor.value.onMeasureAction(10000) + + testableLooper.processAllMessages() + assertThat(lastText).isEqualTo(longText) + } + + @Test + fun testSmallSpaceUseEmpty() { + onMeasureListenerCaptor.value.onMeasureAction(1) + testableLooper.processAllMessages() + + assertThat(lastText).isEmpty() + } + + @Test + fun testSpaceInBetweenUseShortText() { + val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt() + + onMeasureListenerCaptor.value.onMeasureAction(average) + testableLooper.processAllMessages() + + assertThat(lastText).isEqualTo(shortText) + } + + @Test + fun testSwitchBackToLonger() { + onMeasureListenerCaptor.value.onMeasureAction(1) + testableLooper.processAllMessages() + + onMeasureListenerCaptor.value.onMeasureAction(10000) + testableLooper.processAllMessages() + + assertThat(lastText).isEqualTo(longText) + } + + @Test + fun testNoSwitchingWhenFrozen() { + `when`(view.freezeSwitching).thenReturn(true) + + val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt() + onMeasureListenerCaptor.value.onMeasureAction(average) + testableLooper.processAllMessages() + assertThat(lastText).isEqualTo(longText) + + onMeasureListenerCaptor.value.onMeasureAction(1) + testableLooper.processAllMessages() + assertThat(lastText).isEqualTo(longText) + } + + private fun getTextLength(text: CharSequence): Float { + return text.length * CHAR_WIDTH + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java index 9c47f19b20c8..e6dc4db34f91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java @@ -96,6 +96,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { DumpManager mDumpManager; @Mock OverlayManagerTransaction.Builder mTransactionBuilder; + @Mock + Runnable mOnOverlaysApplied; private ThemeOverlayApplier mManager; private boolean mGetOverlayInfoEnabled = true; @@ -103,7 +105,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); - mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(), + mManager = new ThemeOverlayApplier(mOverlayManager, + MoreExecutors.directExecutor(), MoreExecutors.directExecutor(), LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) { @Override protected OverlayManagerTransaction.Builder getTransactionBuilder() { @@ -173,7 +176,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void allCategoriesSpecified_allEnabledExclusively() { mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); verify(mOverlayManager).commit(any()); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { @@ -185,7 +188,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() { mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) { if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) { @@ -202,8 +205,9 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { public void allCategoriesSpecified_enabledForAllUserHandles() { Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES); mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - userHandles); + userHandles, mOnOverlaysApplied); + verify(mOnOverlaysApplied).run(); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), eq(TEST_USER.getIdentifier())); @@ -219,7 +223,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES); mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), - userHandles); + userHandles, mOnOverlaysApplied); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true), @@ -233,7 +237,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { mock(FabricatedOverlay.class) }; mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, - TEST_USER.getIdentifier(), TEST_USER_HANDLES); + TEST_USER.getIdentifier(), TEST_USER_HANDLES, mOnOverlaysApplied); for (FabricatedOverlay overlay : pendingCreation) { verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay)); @@ -247,7 +251,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID); mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); for (OverlayIdentifier overlayPackage : categoryToPackage.values()) { verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), @@ -264,7 +268,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void zeroCategoriesSpecified_allDisabled() { mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); for (String category : THEME_CATEGORIES) { verify(mTransactionBuilder).setEnabled( @@ -279,7 +283,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category")); mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(), - TEST_USER_HANDLES); + TEST_USER_HANDLES, mOnOverlaysApplied); verify(mTransactionBuilder, never()).setEnabled( eq(new OverlayIdentifier("com.example.blah.category")), eq(false), diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index 07d3fc20983f..d3820f06c645 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -161,7 +161,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) @@ -183,7 +183,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED)); mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), null, null), WallpaperManager.FLAG_SYSTEM); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -204,7 +204,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) @@ -240,7 +240,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { .isFalse(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -270,7 +270,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { "android.theme.customization.color_both\":\"0")).isTrue(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -300,7 +300,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { "android.theme.customization.color_both\":\"1")).isTrue(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -327,7 +327,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) .isFalse(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -354,7 +354,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) .isFalse(); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -382,7 +382,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture()); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -411,14 +411,14 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test public void onProfileAdded_setsTheme() { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -428,7 +428,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -438,7 +438,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -450,7 +450,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Color.valueOf(Color.BLUE), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); // Regression test: null events should not reset the internal state and allow colors to be // applied again. @@ -458,11 +458,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED)); mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), - any()); + any(), any()); mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN), null, null), WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), - any()); + any(), any()); } @Test @@ -499,7 +499,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); // Colors were applied during controller initialization. - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); clearInvocations(mThemeOverlayApplier); } @@ -533,7 +533,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); // Colors were applied during controller initialization. - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); clearInvocations(mThemeOverlayApplier); WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), @@ -542,12 +542,12 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { // Defers event because we already have initial colors. verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); // Then event happens after setup phase is over. when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); mDeviceProvisionedListener.getValue().onUserSetupChanged(); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -568,11 +568,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Color.valueOf(Color.RED), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -592,10 +592,10 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Color.valueOf(Color.RED), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM); verify(mThemeOverlayApplier, never()) - .applyCurrentUserOverlays(any(), any(), anyInt(), any()); + .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep(); - verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any()); + verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); } @Test @@ -614,7 +614,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt new file mode 100644 index 000000000000..eebcbe63d004 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.usb + +import android.app.PendingIntent +import android.content.Intent +import android.hardware.usb.IUsbSerialReader +import android.hardware.usb.UsbAccessory +import android.hardware.usb.UsbManager +import android.testing.AndroidTestingRunner +import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS +import androidx.test.filters.SmallTest +import androidx.test.rule.ActivityTestRule +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.lang.Exception + +/** + * UsbPermissionActivityTest + */ +@RunWith(AndroidTestingRunner::class) +@SmallTest +class UsbPermissionActivityTest : SysuiTestCase() { + + class UsbPermissionActivityTestable : UsbPermissionActivity() + + @Rule + @JvmField + var activityRule = ActivityTestRule<UsbPermissionActivityTestable>( + UsbPermissionActivityTestable::class.java, false, false) + + private val activityIntent = Intent(mContext, UsbPermissionActivityTestable::class.java) + .apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + putExtra(UsbManager.EXTRA_PACKAGE, "com.android.systemui") + putExtra(Intent.EXTRA_INTENT, PendingIntent.getBroadcast( + mContext, + 334, + Intent("NO_ACTION"), + PendingIntent.FLAG_MUTABLE)) + putExtra(UsbManager.EXTRA_ACCESSORY, UsbAccessory( + "manufacturer", + "model", + "description", + "version", + "uri", + object : IUsbSerialReader.Stub() { + override fun getSerial(packageName: String): String { + return "serial" + } + })) + } + + @Before + fun setUp() { + activityRule.launchActivity(activityIntent) + } + + @After + fun tearDown() { + activityRule.finishActivity() + } + + @Test + @Throws(Exception::class) + fun testHideNonSystemOverlay() { + assertThat(activityRule.activity.window.attributes.privateFlags and + SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) + .isEqualTo(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java index a34c5986f36c..0e9d96c61e54 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java @@ -16,6 +16,8 @@ package com.android.systemui.util.sensors; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -338,30 +340,25 @@ public class ProximitySensorDualTest extends SysuiTestCase { @Test public void testSecondaryCancelsSecondary() { TestableListener listener = new TestableListener(); - ThresholdSensor.Listener cancelingListener = new ThresholdSensor.Listener() { - @Override - public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent event) { - mProximitySensor.pause(); - } - }; + ThresholdSensor.Listener cancelingListener = event -> mProximitySensor.pause(); mProximitySensor.register(listener); mProximitySensor.register(cancelingListener); - assertNull(listener.mLastEvent); - assertEquals(0, listener.mCallCount); + assertThat(listener.mLastEvent).isNull(); + assertThat(listener.mCallCount).isEqualTo(0); mThresholdSensorPrimary.triggerEvent(true, 0); - assertNull(listener.mLastEvent); - assertEquals(0, listener.mCallCount); + assertThat(listener.mLastEvent).isNull(); + assertThat(listener.mCallCount).isEqualTo(0); mThresholdSensorSecondary.triggerEvent(true, 0); - assertTrue(listener.mLastEvent.getBelow()); - assertEquals(1, listener.mCallCount); + assertThat(listener.mLastEvent.getBelow()).isTrue(); + assertThat(listener.mCallCount).isEqualTo(1); // The proximity sensor should now be canceled. Advancing the clock should do nothing. - assertEquals(0, mFakeExecutor.numPending()); + assertThat(mFakeExecutor.numPending()).isEqualTo(0); mThresholdSensorSecondary.triggerEvent(false, 1); - assertTrue(listener.mLastEvent.getBelow()); - assertEquals(1, listener.mCallCount); + assertThat(listener.mLastEvent.getBelow()).isTrue(); + assertThat(listener.mCallCount).isEqualTo(1); mProximitySensor.unregister(listener); } @@ -372,33 +369,66 @@ public class ProximitySensorDualTest extends SysuiTestCase { TestableListener listener = new TestableListener(); - // WE immediately register the secondary sensor. + // We immediately register the secondary sensor. mProximitySensor.register(listener); - assertFalse(mThresholdSensorPrimary.isPaused()); - assertFalse(mThresholdSensorSecondary.isPaused()); - assertNull(listener.mLastEvent); - assertEquals(0, listener.mCallCount); + assertThat(mThresholdSensorPrimary.isPaused()).isTrue(); + assertThat(mThresholdSensorSecondary.isPaused()).isFalse(); + assertThat(listener.mLastEvent).isNull(); + assertThat(listener.mCallCount).isEqualTo(0); mThresholdSensorPrimary.triggerEvent(true, 0); - assertNull(listener.mLastEvent); - assertEquals(0, listener.mCallCount); + assertThat(listener.mLastEvent).isNull(); + assertThat(listener.mCallCount).isEqualTo(0); mThresholdSensorSecondary.triggerEvent(true, 0); - assertTrue(listener.mLastEvent.getBelow()); - assertEquals(1, listener.mCallCount); + assertThat(listener.mLastEvent.getBelow()).isTrue(); + assertThat(listener.mCallCount).isEqualTo(1); // The secondary sensor should now remain resumed indefinitely. - assertFalse(mThresholdSensorSecondary.isPaused()); + assertThat(mThresholdSensorSecondary.isPaused()).isFalse(); mThresholdSensorSecondary.triggerEvent(false, 1); - assertFalse(listener.mLastEvent.getBelow()); - assertEquals(2, listener.mCallCount); + assertThat(listener.mLastEvent.getBelow()).isFalse(); + assertThat(listener.mCallCount).isEqualTo(2); // The secondary is still running, and not polling with the executor. - assertFalse(mThresholdSensorSecondary.isPaused()); - assertEquals(0, mFakeExecutor.numPending()); + assertThat(mThresholdSensorSecondary.isPaused()).isFalse(); + assertThat(mFakeExecutor.numPending()).isEqualTo(0); mProximitySensor.unregister(listener); } + @Test + public void testSecondaryPausesPrimary() { + TestableListener listener = new TestableListener(); + + mProximitySensor.register(listener); + + assertThat(mThresholdSensorPrimary.isPaused()).isFalse(); + assertThat(mThresholdSensorSecondary.isPaused()).isTrue(); + + mProximitySensor.setSecondarySafe(true); + + assertThat(mThresholdSensorPrimary.isPaused()).isTrue(); + assertThat(mThresholdSensorSecondary.isPaused()).isFalse(); + } + + @Test + public void testSecondaryResumesPrimary() { + mProximitySensor.setSecondarySafe(true); + + TestableListener listener = new TestableListener(); + mProximitySensor.register(listener); + + assertThat(mThresholdSensorPrimary.isPaused()).isTrue(); + assertThat(mThresholdSensorSecondary.isPaused()).isFalse(); + + mProximitySensor.setSecondarySafe(false); + + assertThat(mThresholdSensorPrimary.isPaused()).isFalse(); + assertThat(mThresholdSensorSecondary.isPaused()).isTrue(); + + + } + private static class TestableListener implements ThresholdSensor.Listener { ThresholdSensor.ThresholdSensorEvent mLastEvent; int mCallCount = 0; diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java index 69764227040b..7bb26748a9d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java @@ -31,6 +31,7 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti private final Map<SettingsKey, String> mValues = new HashMap<>(); private final Map<SettingsKey, List<ContentObserver>> mContentObservers = new HashMap<>(); + private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>(); public static final Uri CONTENT_URI = Uri.parse("content://settings/fake"); @@ -55,9 +56,15 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti @Override public void registerContentObserverForUser(Uri uri, boolean notifyDescendents, ContentObserver settingsObserver, int userHandle) { - SettingsKey key = new SettingsKey(userHandle, uri.toString()); - mContentObservers.putIfAbsent(key, new ArrayList<>()); - List<ContentObserver> observers = mContentObservers.get(key); + List<ContentObserver> observers; + if (userHandle == UserHandle.USER_ALL) { + mContentObserversAllUsers.putIfAbsent(uri.toString(), new ArrayList<>()); + observers = mContentObserversAllUsers.get(uri.toString()); + } else { + SettingsKey key = new SettingsKey(userHandle, uri.toString()); + mContentObservers.putIfAbsent(key, new ArrayList<>()); + observers = mContentObservers.get(key); + } observers.add(settingsObserver); } @@ -67,6 +74,10 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti List<ContentObserver> observers = mContentObservers.get(key); observers.remove(settingsObserver); } + for (String key : mContentObserversAllUsers.keySet()) { + List<ContentObserver> observers = mContentObserversAllUsers.get(key); + observers.remove(settingsObserver); + } } @Override @@ -114,6 +125,10 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) { observer.dispatchChange(false, List.of(uri), userHandle); } + for (ContentObserver observer : + mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) { + observer.dispatchChange(false, List.of(uri), userHandle); + } return true; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java index 0d560f237a07..34cae58d30e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.database.ContentObserver; +import android.os.UserHandle; import android.provider.Settings; import android.testing.AndroidTestingRunner; @@ -89,6 +90,16 @@ public class FakeSettingsTest extends SysuiTestCase { } @Test + public void testRegisterContentObserverAllUsers() { + mFakeSettings.registerContentObserverForUser( + mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL); + + mFakeSettings.putString("cat", "hat"); + + verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt()); + } + + @Test public void testUnregisterContentObserver() { mFakeSettings.registerContentObserver("cat", mContentObserver); mFakeSettings.unregisterContentObserver(mContentObserver); @@ -98,4 +109,16 @@ public class FakeSettingsTest extends SysuiTestCase { verify(mContentObserver, never()).dispatchChange( anyBoolean(), any(Collection.class), anyInt()); } + + @Test + public void testUnregisterContentObserverAllUsers() { + mFakeSettings.registerContentObserverForUser( + mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL); + mFakeSettings.unregisterContentObserver(mContentObserver); + + mFakeSettings.putString("cat", "hat"); + + verify(mContentObserver, never()).dispatchChange( + anyBoolean(), any(Collection.class), anyInt()); + } } diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml index 4669a6941cf4..13c5cc9600ee 100644 --- a/packages/VpnDialogs/res/values-as/strings.xml +++ b/packages/VpnDialogs/res/values-as/strings.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="prompt" msgid="3183836924226407828">"সংযোগৰ অনুৰোধ"</string> - <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>এ নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ এটা ভিপিএন সংযোগ ছেট আপ কৰিবলৈ বিচাৰিছে৷ আপুনি কেৱল উৎসটোক বিশ্বাস কৰিলেহে অনুৰোধ স্বীকাৰ কৰিব৷ ভিপিএন সক্ৰিয় থকাৰ সময়ত আপোনাৰ স্ক্ৰীণৰ ওপৰত <br /> <br /> <img src=vpn_icon /> দৃশ্যমান হয়৷"</string> + <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>এ নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ এটা ভিপিএন সংযোগ ছেট আপ কৰিবলৈ বিচাৰিছে৷ আপুনি কেৱল উৎসটোক বিশ্বাস কৰিলেহে অনুৰোধ স্বীকাৰ কৰিব৷ ভিপিএন সক্ৰিয় থকাৰ সময়ত আপোনাৰ স্ক্ৰীনৰ ওপৰত <br /> <br /> <img src=vpn_icon /> দৃশ্যমান হয়৷"</string> <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>এ এটা ভিপিএন সংযোগ ছেট আপ কৰিব বিচাৰে, যিটোৱে ইয়াক নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ দিয়ে। আপুনি উৎসটোক বিশ্বাস কৰিলেহে গ্ৰহণ কৰক। ভিপিএনটো সক্ৰিয় হৈ থকাৰ সময়ত আপোনাৰ স্ক্ৰীনত<br /> <br /> <img src=vpn_icon /> প্ৰদৰ্শিত হয়।"</string> <string name="legacy_title" msgid="192936250066580964">"ভিপিএন সংযোগ হৈ আছে"</string> <string name="session" msgid="6470628549473641030">"ছেশ্বন:"</string> diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index b7c61a0d25cf..51066dd837e2 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -25,9 +25,9 @@ import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGRO import static android.os.UserHandle.USER_SYSTEM; import android.Manifest; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; -import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -187,8 +187,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock(); private boolean mBinding; private boolean mUnbinding; - private int mWaitForEnableRetry; - private int mWaitForDisableRetry; private BluetoothModeChangeHelper mBluetoothModeChangeHelper; @@ -982,14 +980,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (mState == BluetoothAdapter.STATE_ON || mState == BluetoothAdapter.STATE_BLE_ON || mState == BluetoothAdapter.STATE_TURNING_ON - || mState == BluetoothAdapter.STATE_TURNING_OFF) { - Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + || mState == BluetoothAdapter.STATE_TURNING_OFF + || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) { + Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on"); return true; } synchronized (mReceiver) { // waive WRITE_SECURE_SETTINGS permission check - sendEnableMsg(false, - BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName); + sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, + packageName, true); } return true; } @@ -1802,6 +1801,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private class BluetoothHandler extends Handler { boolean mGetNameAddressOnly = false; + private int mWaitForEnableRetry; + private int mWaitForDisableRetry; BluetoothHandler(Looper looper) { super(looper); @@ -1852,11 +1853,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { case MESSAGE_ENABLE: int quietEnable = msg.arg1; + int isBle = msg.arg2; if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) { // We are handling enable or disable right now, wait for it. mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE, - quietEnable, 0), ENABLE_DISABLE_DELAY_MS); + quietEnable, isBle), ENABLE_DISABLE_DELAY_MS); break; } @@ -1871,13 +1873,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { + boolean isHandled = true; int state = mBluetooth.getState(); - if (state == BluetoothAdapter.STATE_BLE_ON) { - Slog.w(TAG, "BT Enable in BLE_ON State, going to ON"); - mBluetooth.onLeServiceUp(mContext.getAttributionSource()); - persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); - break; + switch (state) { + case BluetoothAdapter.STATE_BLE_ON: + if (isBle == 1) { + Slog.i(TAG, "Already at BLE_ON State"); + } else { + Slog.w(TAG, "BT Enable in BLE_ON State, going to ON"); + mBluetooth.onLeServiceUp(mContext.getAttributionSource()); + persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); + } + break; + case BluetoothAdapter.STATE_BLE_TURNING_ON: + case BluetoothAdapter.STATE_TURNING_ON: + case BluetoothAdapter.STATE_ON: + Slog.i(TAG, "MESSAGE_ENABLE: already enabled"); + break; + default: + isHandled = false; + break; } + if (isHandled) break; } } catch (RemoteException e) { Slog.e(TAG, "", e); @@ -2479,7 +2496,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { try { foregroundUser = ActivityManager.getCurrentUser(); valid = (callingUser == foregroundUser) || parentUser == foregroundUser - || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid; + || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid + || callingAppId == Process.SHELL_UID; if (DBG && !valid) { Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser=" + callingUser + " parentUser=" + parentUser + " foregroundUser=" @@ -2642,7 +2660,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } private void sendEnableMsg(boolean quietMode, int reason, String packageName) { - mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0)); + sendEnableMsg(quietMode, reason, packageName, false); + } + + private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) { + mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, + isBle ? 1 : 0)); addActiveLog(reason, packageName, true); mLastEnabledTime = SystemClock.elapsedRealtime(); } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 0c633cacda92..7ba032f683b8 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -478,7 +478,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { for (int uid : uidsToRemove) { FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, -1, uid, FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__REMOVED); - mStats.removeIsolatedUidLocked(uid, SystemClock.elapsedRealtime(), + mStats.maybeRemoveIsolatedUidLocked(uid, SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); } mStats.clearPendingRemovedUids(); diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 5c9d38515e49..2e3e635c1157 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -94,8 +94,6 @@ final class CoreSettingsObserver extends ContentObserver { sGlobalSettingToTypeMap.put( Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, String.class); sGlobalSettingToTypeMap.put( - Settings.Global.ANGLE_ALLOWLIST, String.class); - sGlobalSettingToTypeMap.put( Settings.Global.ANGLE_EGL_FEATURES, String.class); sGlobalSettingToTypeMap.put( Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 5c19ceb7067a..ff480d1f614c 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -72,6 +72,7 @@ import static com.android.server.am.AppProfiler.TAG_PSS; import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; +import android.annotation.IntDef; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; @@ -114,6 +115,8 @@ import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.WindowProcessController; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayDeque; import java.util.ArrayList; @@ -171,6 +174,27 @@ public class OomAdjuster { @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) static final long USE_SHORT_FGS_USAGE_INTERACTION_TIME = 183972877L; + static final int CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY = 0; + static final int CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY = 1; + static final int CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME = 2; + + @IntDef(prefix = { "CACHED_COMPAT_CHANGE_" }, value = { + CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY, + CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY, + CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME, + }) + @Retention(RetentionPolicy.SOURCE) + static @interface CachedCompatChangeId{} + + /** + * Mapping from CACHED_COMPAT_CHANGE_* to the actual compat change id. + */ + static final long[] CACHED_COMPAT_CHANGE_IDS_MAPPING = new long[] { + PROCESS_CAPABILITY_CHANGE_ID, + CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, + USE_SHORT_FGS_USAGE_INTERACTION_TIME, + }; + /** * For some direct access we need to power manager. */ @@ -368,6 +392,12 @@ public class OomAdjuster { return mPlatformCompatCache; } + boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, ApplicationInfo app, + boolean defaultValue) { + return getPlatformCompatCache().isChangeEnabled( + CACHED_COMPAT_CHANGE_IDS_MAPPING[cachedCompatChangeId], app, defaultValue); + } + OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) { this(service, processList, activeUids, createAdjusterThread()); } @@ -1929,12 +1959,8 @@ public class OomAdjuster { (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0; - boolean enabled = false; - try { - enabled = getPlatformCompatCache().isChangeEnabled( - CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo); - } catch (RemoteException e) { - } + final boolean enabled = state.getCachedCompatChange( + CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY); if (enabled) { capabilityFromFGS |= (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA) @@ -2151,12 +2177,8 @@ public class OomAdjuster { // to client's state. clientProcState = PROCESS_STATE_BOUND_TOP; state.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP); - boolean enabled = false; - try { - enabled = getPlatformCompatCache().isChangeEnabled( - PROCESS_CAPABILITY_CHANGE_ID, client.info); - } catch (RemoteException e) { - } + final boolean enabled = cstate.getCachedCompatChange( + CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY); if (enabled) { if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { // TOP process passes all capabilities to the service. @@ -2800,8 +2822,8 @@ public class OomAdjuster { state.setProcStateChanged(true); } } else if (state.hasReportedInteraction()) { - final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled( - USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false); + final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange( + CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME); final long interactionThreshold = fgsInteractionChangeEnabled ? mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S : mConstants.USAGE_STATS_INTERACTION_INTERVAL_PRE_S; @@ -2811,8 +2833,8 @@ public class OomAdjuster { maybeUpdateUsageStatsLSP(app, nowElapsed); } } else { - final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled( - USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false); + final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange( + CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME); final long interactionThreshold = fgsInteractionChangeEnabled ? mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S : mConstants.SERVICE_USAGE_INTERACTION_TIME_PRE_S; @@ -2901,8 +2923,8 @@ public class OomAdjuster { if (mService.mUsageStatsService == null) { return; } - final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled( - USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false); + final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange( + CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME); boolean isInteraction; // To avoid some abuse patterns, we are going to be careful about what we consider // to be an app interaction. Being the top activity doesn't count while the display diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index dc6bcd8ab9de..d4474d663769 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -21,6 +21,7 @@ import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; +import static com.android.server.am.OomAdjuster.CachedCompatChangeId; import static com.android.server.am.ProcessRecord.TAG; import android.annotation.ElapsedRealtimeLong; @@ -377,6 +378,16 @@ final class ProcessStateRecord { @GuardedBy("mService") private int mCachedIsReceivingBroadcast = VALUE_INVALID; + /** + * Cache the return value of PlatformCompat.isChangeEnabled(). + */ + @GuardedBy("mService") + private int[] mCachedCompatChanges = new int[] { + VALUE_INVALID, // CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY + VALUE_INVALID, // CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY + VALUE_INVALID, // CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME + }; + @GuardedBy("mService") private int mCachedAdj = ProcessList.INVALID_ADJ; @GuardedBy("mService") @@ -1009,6 +1020,16 @@ final class ProcessStateRecord { } @GuardedBy("mService") + boolean getCachedCompatChange(@CachedCompatChangeId int cachedCompatChangeId) { + if (mCachedCompatChanges[cachedCompatChangeId] == VALUE_INVALID) { + mCachedCompatChanges[cachedCompatChangeId] = mService.mOomAdjuster + .isChangeEnabled(cachedCompatChangeId, mApp.info, false /* default */) + ? VALUE_TRUE : VALUE_FALSE; + } + return mCachedCompatChanges[cachedCompatChangeId] == VALUE_TRUE; + } + + @GuardedBy("mService") void computeOomAdjFromActivitiesIfNecessary(OomAdjuster.ComputeOomAdjWindowCallback callback, int adj, boolean foregroundActivities, boolean hasVisibleActivities, int procState, int schedGroup, int appUid, int logUid, int processCurTop) { @@ -1088,6 +1109,9 @@ final class ProcessStateRecord { mCurSchedGroup = mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; mCurProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState = PROCESS_STATE_NONEXISTENT; + for (int i = 0; i < mCachedCompatChanges.length; i++) { + mCachedCompatChanges[i] = VALUE_INVALID; + } } @GuardedBy("mService") diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index af8d7a6a282b..3003c520254b 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -272,6 +272,13 @@ public final class GameManagerService extends IGameManagerService.Stub { "com.android.graphics.intervention.wm.allowDownscale"; /** + * Metadata that can be included in the app manifest to allow/disallow any ANGLE + * interventions. Default value is TRUE. + */ + public static final String METADATA_ANGLE_ALLOW_ANGLE = + "com.android.graphics.intervention.angle.allowAngle"; + + /** * Metadata that needs to be included in the app manifest to OPT-IN to PERFORMANCE mode. * This means the app will assume full responsibility for the experience provided by this * mode and the system will enable no window manager downscaling. @@ -294,6 +301,7 @@ public final class GameManagerService extends IGameManagerService.Stub { private boolean mPerfModeOptedIn; private boolean mBatteryModeOptedIn; private boolean mAllowDownscale; + private boolean mAllowAngle; GamePackageConfiguration(String packageName, int userId) { mPackageName = packageName; @@ -305,10 +313,12 @@ public final class GameManagerService extends IGameManagerService.Stub { mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE); mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE); mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true); + mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true); } else { mPerfModeOptedIn = false; mBatteryModeOptedIn = false; mAllowDownscale = true; + mAllowAngle = true; } } catch (PackageManager.NameNotFoundException e) { // Not all packages are installed, hence ignore those that are not installed yet. @@ -340,14 +350,26 @@ public final class GameManagerService extends IGameManagerService.Stub { public static final String MODE_KEY = "mode"; public static final String SCALING_KEY = "downscaleFactor"; public static final String DEFAULT_SCALING = "1.0"; + public static final String ANGLE_KEY = "useAngle"; private final @GameMode int mGameMode; private final String mScaling; + private final boolean mUseAngle; GameModeConfiguration(KeyValueListParser parser) { mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED); - mScaling = !mAllowDownscale || isGameModeOptedIn(mGameMode) + // isGameModeOptedIn() returns if an app will handle all of the changes necessary + // for a particular game mode. If so, the Android framework (i.e. + // GameManagerService) will not do anything for the app (like window scaling or + // using ANGLE). + mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode) ? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING); + // We only want to use ANGLE if: + // - We're allowed to use ANGLE (the app hasn't opted out via the manifest) AND + // - The app has not opted in to performing the work itself AND + // - The Phenotype config has enabled it. + mUseAngle = mAllowAngle && !willGamePerformOptimizations(mGameMode) + && parser.getBoolean(ANGLE_KEY, false); } public int getGameMode() { @@ -358,6 +380,10 @@ public final class GameManagerService extends IGameManagerService.Stub { return mScaling; } + public boolean getUseAngle() { + return mUseAngle; + } + public boolean isValid() { return (mGameMode == GameManager.GAME_MODE_PERFORMANCE || mGameMode == GameManager.GAME_MODE_BATTERY) @@ -368,7 +394,8 @@ public final class GameManagerService extends IGameManagerService.Stub { * @hide */ public String toString() { - return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + "]"; + return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + ",Use Angle:" + + mUseAngle + "]"; } /** @@ -384,13 +411,14 @@ public final class GameManagerService extends IGameManagerService.Stub { } /** - * Gets whether a package has opted into a game mode via its manifest. + * Returns if the app will assume full responsibility for the experience provided by this + * mode. If True, the system will not perform any interventions for the app. * * @return True if the app package has specified in its metadata either: * "com.android.app.gamemode.performance.enabled" or * "com.android.app.gamemode.battery.enabled" with a value of "true" */ - public boolean isGameModeOptedIn(@GameMode int gameMode) { + public boolean willGamePerformOptimizations(@GameMode int gameMode) { return (mBatteryModeOptedIn && gameMode == GameManager.GAME_MODE_BATTERY) || (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE); } @@ -631,7 +659,34 @@ public final class GameManagerService extends IGameManagerService.Stub { mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY); } } - updateCompatModeDownscale(packageName, gameMode); + updateInterventions(packageName, gameMode); + } + + /** + * Get if ANGLE is enabled for the package for the currently enabled game mode. + * Checks that the caller has {@link android.Manifest.permission#MANAGE_GAME_MODE}. + */ + @Override + @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE) + public @GameMode boolean getAngleEnabled(String packageName, int userId) + throws SecurityException { + final int gameMode = getGameMode(packageName, userId); + if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) { + return false; + } + + synchronized (mDeviceConfigLock) { + final GamePackageConfiguration config = mConfigs.get(packageName); + if (config == null) { + return false; + } + GamePackageConfiguration.GameModeConfiguration gameModeConfiguration = + config.getGameModeConfiguration(gameMode); + if (gameModeConfiguration == null) { + return false; + } + return gameModeConfiguration.getUseAngle(); + } } /** @@ -753,7 +808,7 @@ public final class GameManagerService extends IGameManagerService.Stub { if (DEBUG) { Slog.v(TAG, dumpDeviceConfigs()); } - if (packageConfig.isGameModeOptedIn(gameMode)) { + if (packageConfig.willGamePerformOptimizations(gameMode)) { disableCompatScale(packageName); return; } @@ -782,6 +837,17 @@ public final class GameManagerService extends IGameManagerService.Stub { return (bitField & modeToBitmask(gameMode)) != 0; } + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + private void updateUseAngle(String packageName, @GameMode int gameMode) { + // TODO (b/188475576): Nothing to do yet. Remove if it's still empty when we're ready to + // ship. + } + + private void updateInterventions(String packageName, @GameMode int gameMode) { + updateCompatModeDownscale(packageName, gameMode); + updateUseAngle(packageName, gameMode); + } + /** * @hide */ @@ -839,11 +905,11 @@ public final class GameManagerService extends IGameManagerService.Stub { if (newGameMode != gameMode) { setGameMode(packageName, newGameMode, userId); } - updateCompatModeDownscale(packageName, gameMode); + updateInterventions(packageName, gameMode); } } } catch (Exception e) { - Slog.e(TAG, "Failed to update compat modes for user: " + userId); + Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e); } } @@ -851,7 +917,7 @@ public final class GameManagerService extends IGameManagerService.Stub { final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(0, userId); return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category - == ApplicationInfo.CATEGORY_GAME) + == ApplicationInfo.CATEGORY_GAME) .map(e -> e.packageName) .toArray(String[]::new); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 8961a5a05546..5ecdfe49cdf7 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1719,11 +1719,10 @@ import java.util.concurrent.atomic.AtomicBoolean; if (client == null) { return; } - Log.w(TAG, "Speaker client died"); - if (removeCommunicationRouteClient(client.getBinder(), false) - != null) { - onUpdateCommunicationRoute("onCommunicationRouteClientDied"); - } + Log.w(TAG, "Communication client died"); + setCommunicationRouteForClient( + client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED, + "onCommunicationRouteClientDied"); } /** diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 34e2578f7855..5e67c5438550 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2823,8 +2823,8 @@ public class AudioService extends IAudioService.Stub if (uid == android.os.Process.SYSTEM_UID) { uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid)); } - if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + // validate calling package and app op + if (!checkNoteAppOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)) { return; } @@ -3547,8 +3547,7 @@ public class AudioService extends IAudioService.Stub if (uid == android.os.Process.SYSTEM_UID) { uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid)); } - if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + if (!checkNoteAppOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)) { return; } @@ -3983,8 +3982,7 @@ public class AudioService extends IAudioService.Stub uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); } // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting. - if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + if (!mute && !checkNoteAppOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)) { return; } if (userId != UserHandle.getCallingUserId() && @@ -4115,8 +4113,7 @@ public class AudioService extends IAudioService.Stub ? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE); // If OP_MUTE_MICROPHONE is set, disallow unmuting. - if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage) - != AppOpsManager.MODE_ALLOWED) { + if (!on && !checkNoteAppOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)) { mmi.set(MediaMetrics.Property.EARLY_RETURN, "disallow unmuting").record(); return; } @@ -5295,6 +5292,10 @@ public class AudioService extends IAudioService.Stub // TODO investigate internal users due to deprecation of SDK API /** @see AudioManager#setBluetoothA2dpOn(boolean) */ public void setBluetoothA2dpOn(boolean on) { + if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) { + return; + } + // for logging only final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); @@ -5320,6 +5321,10 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#startBluetoothSco() */ public void startBluetoothSco(IBinder cb, int targetSdkVersion) { + if (!checkAudioSettingsPermission("startBluetoothSco()")) { + return; + } + final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final int scoAudioMode = @@ -5342,6 +5347,10 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#startBluetoothScoVirtualCall() */ public void startBluetoothScoVirtualCall(IBinder cb) { + if (!checkAudioSettingsPermission("startBluetoothScoVirtualCall()")) { + return; + } + final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()") @@ -10522,4 +10531,31 @@ public class AudioService extends IAudioService.Stub } mFullVolumeDevices.remove(audioSystemDeviceOut); } + + //==================== + // Helper functions for app ops + //==================== + /** + * Validates, and notes an app op for a given uid and package name. + * Validation comes from exception catching: a security exception indicates the package + * doesn't exist, an IAE indicates the uid and package don't match. The code only checks + * if exception was thrown for robustness to code changes in op validation + * @param op the app op to check + * @param uid the uid of the caller + * @param packageName the package to check + * @return true if the origin of the call is valid (no uid / package mismatch) and the caller + * is allowed to perform the operation + */ + private boolean checkNoteAppOp(int op, int uid, String packageName) { + try { + if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) { + return false; + } + } catch (Exception e) { + Log.e(TAG, "Error noting op:" + op + " on uid:" + uid + " for package:" + + packageName, e); + return false; + } + return true; + } } diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 0cd2e3d0ff59..b42f8980d1c0 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -206,7 +206,7 @@ public class AuthService extends SystemService { } @Override - public void authenticate(IBinder token, long sessionId, int userId, + public long authenticate(IBinder token, long sessionId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) throws RemoteException { // Only allow internal clients to authenticate with a different userId. @@ -223,18 +223,18 @@ public class AuthService extends SystemService { if (!checkAppOps(callingUid, opPackageName, "authenticate()")) { authenticateFastFail("Denied by app ops: " + opPackageName, receiver); - return; + return -1; } if (token == null || receiver == null || opPackageName == null || promptInfo == null) { authenticateFastFail( "Unable to authenticate, one or more null arguments", receiver); - return; + return -1; } if (!Utils.isForeground(callingUid, callingPid)) { authenticateFastFail("Caller is not foreground: " + opPackageName, receiver); - return; + return -1; } if (promptInfo.containsTestConfigurations()) { @@ -251,7 +251,7 @@ public class AuthService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { - mBiometricService.authenticate( + return mBiometricService.authenticate( token, sessionId, userId, receiver, opPackageName, promptInfo); } finally { Binder.restoreCallingIdentity(identity); @@ -270,7 +270,7 @@ public class AuthService extends SystemService { } @Override - public void cancelAuthentication(IBinder token, String opPackageName) + public void cancelAuthentication(IBinder token, String opPackageName, long requestId) throws RemoteException { checkPermission(); @@ -281,7 +281,7 @@ public class AuthService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { - mBiometricService.cancelAuthentication(token, opPackageName); + mBiometricService.cancelAuthentication(token, opPackageName, requestId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index bdde980f5cae..0da6a1ba3109 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -128,6 +128,7 @@ public final class AuthSession implements IBinder.DeathRecipient { @VisibleForTesting final IBinder mToken; // Info to be shown on BiometricDialog when all cookies are returned. @VisibleForTesting final PromptInfo mPromptInfo; + private final long mRequestId; private final long mOperationId; private final int mUserId; private final IBiometricSensorReceiver mSensorReceiver; @@ -142,6 +143,8 @@ public final class AuthSession implements IBinder.DeathRecipient { private @BiometricMultiSensorMode int mMultiSensorMode; private @MultiSensorState int mMultiSensorState; private int[] mSensors; + // TODO(b/197265902): merge into state + private boolean mCancelled; // For explicit confirmation, do not send to keystore until the user has confirmed // the authentication. private byte[] mTokenEscrow; @@ -162,6 +165,7 @@ public final class AuthSession implements IBinder.DeathRecipient { @NonNull ClientDeathReceiver clientDeathReceiver, @NonNull PreAuthInfo preAuthInfo, @NonNull IBinder token, + long requestId, long operationId, int userId, @NonNull IBiometricSensorReceiver sensorReceiver, @@ -179,6 +183,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mClientDeathReceiver = clientDeathReceiver; mPreAuthInfo = preAuthInfo; mToken = token; + mRequestId = requestId; mOperationId = operationId; mUserId = userId; mSensorReceiver = sensorReceiver; @@ -187,6 +192,7 @@ public final class AuthSession implements IBinder.DeathRecipient { mPromptInfo = promptInfo; mDebugEnabled = debugEnabled; mFingerprintSensorProperties = fingerprintSensorProperties; + mCancelled = false; try { mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */); @@ -233,7 +239,7 @@ public final class AuthSession implements IBinder.DeathRecipient { Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id); } sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, - mUserId, mSensorReceiver, mOpPackageName, cookie, + mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie, mPromptInfo.isAllowBackgroundAuthentication()); } } @@ -255,8 +261,9 @@ public final class AuthSession implements IBinder.DeathRecipient { true /* credentialAllowed */, false /* requireConfirmation */, mUserId, - mOpPackageName, mOperationId, + mOpPackageName, + mRequestId, mMultiSensorMode); } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) { // Some combination of biometric or biometric|credential is requested @@ -270,6 +277,11 @@ public final class AuthSession implements IBinder.DeathRecipient { } void onCookieReceived(int cookie) { + if (mCancelled) { + Slog.w(TAG, "Received cookie but already cancelled (ignoring): " + cookie); + return; + } + for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { sensor.goToStateCookieReturnedIfCookieMatches(cookie); } @@ -301,8 +313,9 @@ public final class AuthSession implements IBinder.DeathRecipient { mPreAuthInfo.shouldShowCredential(), requireConfirmation, mUserId, - mOpPackageName, mOperationId, + mOpPackageName, + mRequestId, mMultiSensorMode); mState = STATE_AUTH_STARTED; } catch (RemoteException e) { @@ -369,7 +382,7 @@ public final class AuthSession implements IBinder.DeathRecipient { final boolean shouldCancel = filter.apply(sensor); Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel); if (shouldCancel) { - sensor.goToStateCancelling(mToken, mOpPackageName); + sensor.goToStateCancelling(mToken, mOpPackageName, mRequestId); } } catch (RemoteException e) { Slog.e(TAG, "Unable to cancel authentication"); @@ -425,8 +438,9 @@ public final class AuthSession implements IBinder.DeathRecipient { true /* credentialAllowed */, false /* requireConfirmation */, mUserId, - mOpPackageName, mOperationId, + mOpPackageName, + mRequestId, mMultiSensorMode); } else { mClientReceiver.onError(modality, error, vendorCode); @@ -775,6 +789,8 @@ public final class AuthSession implements IBinder.DeathRecipient { * @return true if this AuthSession is finished, e.g. should be set to null */ boolean onCancelAuthSession(boolean force) { + mCancelled = true; + final boolean authStarted = mState == STATE_AUTH_CALLED || mState == STATE_AUTH_STARTED || mState == STATE_AUTH_STARTED_UI_SHOWING; @@ -820,6 +836,7 @@ public final class AuthSession implements IBinder.DeathRecipient { return Utils.isCredentialRequested(mPromptInfo); } + @VisibleForTesting boolean allCookiesReceived() { final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie(); Slog.d(TAG, "Remaining cookies: " + remainingCookies); @@ -839,6 +856,10 @@ public final class AuthSession implements IBinder.DeathRecipient { return mState; } + long getRequestId() { + return mRequestId; + } + private int statsModality() { int modality = 0; @@ -901,7 +922,9 @@ public final class AuthSession implements IBinder.DeathRecipient { @Override public String toString() { return "State: " + mState + + ", cancelled: " + mCancelled + ", isCrypto: " + isCrypto() - + ", PreAuthInfo: " + mPreAuthInfo; + + ", PreAuthInfo: " + mPreAuthInfo + + ", requestId: " + mRequestId; } } diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java index 8a842b53d8e8..0333c3e247c0 100644 --- a/services/core/java/com/android/server/biometrics/BiometricSensor.java +++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java @@ -108,11 +108,11 @@ public abstract class BiometricSensor { void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication) + long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mCookie = cookie; impl.prepareForAuthentication(requireConfirmation, token, - sessionId, userId, sensorReceiver, opPackageName, mCookie, + sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie, allowBackgroundAuthentication); mSensorState = STATE_WAITING_FOR_COOKIE; } @@ -129,8 +129,9 @@ public abstract class BiometricSensor { mSensorState = STATE_AUTHENTICATING; } - void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException { - impl.cancelAuthenticationFromService(token, opPackageName); + void goToStateCancelling(IBinder token, String opPackageName, long requestId) + throws RemoteException { + impl.cancelAuthenticationFromService(token, opPackageName, requestId); mSensorState = STATE_CANCELING; } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index b1d300cd838e..e0775d48b42f 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -83,6 +83,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; /** * System service that arbitrates the modality for BiometricPrompt to use. @@ -115,6 +116,7 @@ public class BiometricService extends SystemService { final SettingObserver mSettingObserver; private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks; private final Random mRandom = new Random(); + @NonNull private final AtomicLong mRequestCounter; @VisibleForTesting IStatusBarService mStatusBarService; @@ -194,6 +196,7 @@ public class BiometricService extends SystemService { SomeArgs args = (SomeArgs) msg.obj; handleAuthenticate( (IBinder) args.arg1 /* token */, + (long) args.arg6 /* requestId */, (long) args.arg2 /* operationId */, args.argi1 /* userid */, (IBiometricServiceReceiver) args.arg3 /* receiver */, @@ -204,7 +207,9 @@ public class BiometricService extends SystemService { } case MSG_CANCEL_AUTHENTICATION: { - handleCancelAuthentication(); + SomeArgs args = (SomeArgs) msg.obj; + handleCancelAuthentication((long) args.arg3 /* requestId */); + args.recycle(); break; } @@ -683,13 +688,13 @@ public class BiometricService extends SystemService { } @Override // Binder call - public void authenticate(IBinder token, long operationId, int userId, + public long authenticate(IBinder token, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { checkInternalPermission(); if (token == null || receiver == null || opPackageName == null || promptInfo == null) { Slog.e(TAG, "Unable to authenticate, one or more null arguments"); - return; + return -1; } if (!Utils.isValidAuthenticatorConfig(promptInfo)) { @@ -706,6 +711,8 @@ public class BiometricService extends SystemService { } } + final long requestId = mRequestCounter.incrementAndGet(); + SomeArgs args = SomeArgs.obtain(); args.arg1 = token; args.arg2 = operationId; @@ -713,15 +720,23 @@ public class BiometricService extends SystemService { args.arg3 = receiver; args.arg4 = opPackageName; args.arg5 = promptInfo; + args.arg6 = requestId; mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget(); + + return requestId; } @Override // Binder call - public void cancelAuthentication(IBinder token, String opPackageName) { + public void cancelAuthentication(IBinder token, String opPackageName, long requestId) { checkInternalPermission(); - mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget(); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = token; + args.arg2 = opPackageName; + args.arg3 = requestId; + + mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget(); } @Override // Binder call @@ -1111,6 +1126,10 @@ public class BiometricService extends SystemService { return Settings.Secure.getInt(context.getContentResolver(), CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0; } + + public AtomicLong getRequestGenerator() { + return new AtomicLong(0); + } } /** @@ -1136,6 +1155,7 @@ public class BiometricService extends SystemService { mEnabledOnKeyguardCallbacks = new ArrayList<>(); mSettingObserver = mInjector.getSettingObserver(context, mHandler, mEnabledOnKeyguardCallbacks); + mRequestCounter = mInjector.getRequestGenerator(); // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't // need to depend on context. We can remove this code once the advanced logic is enabled @@ -1349,7 +1369,7 @@ public class BiometricService extends SystemService { mCurrentAuthSession.onCookieReceived(cookie); } - private void handleAuthenticate(IBinder token, long operationId, int userId, + private void handleAuthenticate(IBinder token, long requestId, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { mHandler.post(() -> { try { @@ -1360,7 +1380,8 @@ public class BiometricService extends SystemService { final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first - + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo); + + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo + + " requestId: " + requestId); if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) { // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but @@ -1372,8 +1393,8 @@ public class BiometricService extends SystemService { promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL); } - authenticateInternal(token, operationId, userId, receiver, opPackageName, - promptInfo, preAuthInfo); + authenticateInternal(token, requestId, operationId, userId, receiver, + opPackageName, promptInfo, preAuthInfo); } else { receiver.onError(preAuthStatus.first /* modality */, preAuthStatus.second /* errorCode */, @@ -1394,7 +1415,7 @@ public class BiometricService extends SystemService { * Note that this path is NOT invoked when the BiometricPrompt "Try again" button is pressed. * In that case, see {@link #handleOnTryAgainPressed()}. */ - private void authenticateInternal(IBinder token, long operationId, int userId, + private void authenticateInternal(IBinder token, long requestId, long operationId, int userId, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo, PreAuthInfo preAuthInfo) { Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo); @@ -1412,9 +1433,9 @@ public class BiometricService extends SystemService { final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId); mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver, - mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId, - mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled, - mInjector.getFingerprintSensorProperties(getContext())); + mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, requestId, + operationId, userId, mBiometricSensorReceiver, receiver, opPackageName, promptInfo, + debugEnabled, mInjector.getFingerprintSensorProperties(getContext())); try { mCurrentAuthSession.goToInitialState(); } catch (RemoteException e) { @@ -1422,11 +1443,21 @@ public class BiometricService extends SystemService { } } - private void handleCancelAuthentication() { + private void handleCancelAuthentication(long requestId) { if (mCurrentAuthSession == null) { Slog.e(TAG, "handleCancelAuthentication: AuthSession is null"); return; } + if (mCurrentAuthSession.getRequestId() != requestId) { + // TODO: actually cancel the operation + // This can happen if the operation has been queued, but is cancelled before + // it reaches the head of the scheduler. Consider it a programming error for now + // and ignore it. + Slog.e(TAG, "handleCancelAuthentication: AuthSession mismatch current requestId: " + + mCurrentAuthSession.getRequestId() + " cancel for: " + requestId + + " (ignoring cancellation)"); + return; + } final boolean finished = mCurrentAuthSession.onCancelAuthSession(false /* force */); if (finished) { diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java index 3eb6f4ae48a2..9764a167fbbf 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java @@ -26,6 +26,8 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import java.util.ArrayList; +import java.util.List; import java.util.NoSuchElementException; /** @@ -70,26 +72,32 @@ public abstract class BaseClientMonitor extends LoggableMonitor } /** Holder for wrapping multiple handlers into a single Callback. */ - protected static class CompositeCallback implements Callback { + public static class CompositeCallback implements Callback { @NonNull - private final Callback[] mCallbacks; + private final List<Callback> mCallbacks; public CompositeCallback(@NonNull Callback... callbacks) { - mCallbacks = callbacks; + mCallbacks = new ArrayList<>(); + + for (Callback callback : callbacks) { + if (callback != null) { + mCallbacks.add(callback); + } + } } @Override public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { - for (int i = 0; i < mCallbacks.length; i++) { - mCallbacks[i].onClientStarted(clientMonitor); + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onClientStarted(clientMonitor); } } @Override public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { - for (int i = mCallbacks.length - 1; i >= 0; i--) { - mCallbacks[i].onClientFinished(clientMonitor, success); + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + mCallbacks.get(i).onClientFinished(clientMonitor, success); } } } @@ -101,6 +109,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor private final int mSensorId; // sensorId as configured by the framework @Nullable private IBinder mToken; + private long mRequestId; @Nullable private ClientMonitorCallbackConverter mListener; // Currently only used for authentication client. The cookie generated by BiometricService // is never 0. @@ -154,6 +163,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor mSequentialId = sCount++; mContext = context; mToken = token; + mRequestId = -1; mListener = listener; mTargetUserId = userId; mOwner = owner; @@ -254,10 +264,33 @@ public abstract class BaseClientMonitor extends LoggableMonitor return mToken; } - public final int getSensorId() { + public int getSensorId() { return mSensorId; } + /** Unique request id. */ + public final long getRequestId() { + return mRequestId; + } + + /** If a unique id has been set via {@link #setRequestId(long)} */ + public final boolean hasRequestId() { + return mRequestId > 0; + } + + /** + * A unique identifier used to tie this operation to a request (i.e an API invocation). + * + * Subclasses should not call this method if this operation does not have a direct + * correspondence to a request and {@link #hasRequestId()} will return false. + */ + protected final void setRequestId(long id) { + if (id <= 0) { + throw new IllegalArgumentException("request id must be positive"); + } + mRequestId = id; + } + @VisibleForTesting public Callback getCallback() { return mCallback; @@ -270,6 +303,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor + ", proto=" + getProtoEnum() + ", owner=" + getOwnerString() + ", cookie=" + getCookie() + + ", requestId=" + getRequestId() + ", userId=" + getTargetUserId() + "}"; } } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java index feb9e2a5b03f..361ec40f2877 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -643,22 +643,18 @@ public class BiometricScheduler { /** * Requests to cancel authentication or detection. * @param token from the caller, should match the token passed in when requesting authentication + * @param requestId the id returned when requesting authentication */ - public void cancelAuthenticationOrDetection(IBinder token) { - if (mCurrentOperation == null) { - Slog.e(getTag(), "Unable to cancel authentication, null operation"); - return; - } - final boolean isCorrectClient = isAuthenticationOrDetectionOperation(mCurrentOperation); - final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token; - - Slog.d(getTag(), "cancelAuthenticationOrDetection, isCorrectClient: " + isCorrectClient - + ", tokenMatches: " + tokenMatches); + public void cancelAuthenticationOrDetection(IBinder token, long requestId) { + Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId + + " current: " + mCurrentOperation + + " stack size: " + mPendingOperations.size()); - if (isCorrectClient && tokenMatches) { + if (mCurrentOperation != null + && canCancelAuthOperation(mCurrentOperation, token, requestId)) { Slog.d(getTag(), "Cancelling: " + mCurrentOperation); cancelInternal(mCurrentOperation); - } else if (!isCorrectClient) { + } else { // Look through the current queue for all authentication clients for the specified // token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking // all of them, instead of just the first one, since the API surface currently doesn't @@ -666,8 +662,7 @@ public class BiometricScheduler { // process. However, this generally does not happen anyway, and would be a class of // bugs on its own. for (Operation operation : mPendingOperations) { - if (isAuthenticationOrDetectionOperation(operation) - && operation.mClientMonitor.getToken() == token) { + if (canCancelAuthOperation(operation, token, requestId)) { Slog.d(getTag(), "Marking " + operation + " as STATE_WAITING_IN_QUEUE_CANCELING"); operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING; @@ -676,10 +671,26 @@ public class BiometricScheduler { } } - private boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) { - final boolean isAuthentication = operation.mClientMonitor - instanceof AuthenticationConsumer; - final boolean isDetection = operation.mClientMonitor instanceof DetectionConsumer; + private static boolean canCancelAuthOperation(Operation operation, IBinder token, + long requestId) { + // TODO: restrict callers that can cancel without requestId (negative value)? + return isAuthenticationOrDetectionOperation(operation) + && operation.mClientMonitor.getToken() == token + && isMatchingRequestId(operation, requestId); + } + + // By default, monitors are not associated with a request id to retain the original + // behavior (i.e. if no requestId is explicitly set then assume it matches) + private static boolean isMatchingRequestId(Operation operation, long requestId) { + return !operation.mClientMonitor.hasRequestId() + || operation.mClientMonitor.getRequestId() == requestId; + } + + private static boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) { + final boolean isAuthentication = + operation.mClientMonitor instanceof AuthenticationConsumer; + final boolean isDetection = + operation.mClientMonitor instanceof DetectionConsumer; return isAuthentication || isDetection; } diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java index a15e14b79e30..9191b8b55989 100644 --- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java @@ -31,7 +31,7 @@ import java.util.Arrays; /** * A class to keep track of the enrollment state for a given client. */ -public abstract class EnrollClient<T> extends AcquisitionClient<T> { +public abstract class EnrollClient<T> extends AcquisitionClient<T> implements EnrollmentModifier { private static final String TAG = "Biometrics/EnrollClient"; @@ -40,6 +40,7 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> { protected final BiometricUtils mBiometricUtils; private long mEnrollmentStartTimeMs; + private final boolean mHasEnrollmentsBeforeStarting; /** * @return true if the user has already enrolled the maximum number of templates. @@ -56,6 +57,18 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> { mBiometricUtils = utils; mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length); mTimeoutSec = timeoutSec; + mHasEnrollmentsBeforeStarting = hasEnrollments(); + } + + @Override + public boolean hasEnrollmentStateChanged() { + final boolean hasEnrollmentsNow = hasEnrollments(); + return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting; + } + + @Override + public boolean hasEnrollments() { + return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty(); } public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) { diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java b/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java new file mode 100644 index 000000000000..c2f909b08bb6 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors; + +/** + * Interface for {@link BaseClientMonitor} subclasses that affect the state of enrollment. + */ +public interface EnrollmentModifier { + + /** + * Callers should typically check this after + * {@link BaseClientMonitor.Callback#onClientFinished(BaseClientMonitor, boolean)} + * + * @return true if the user has gone from: + * 1) none-enrolled --> enrolled + * 2) enrolled --> none-enrolled + * but NOT any-enrolled --> more-enrolled + */ + boolean hasEnrollmentStateChanged(); + + /** + * @return true if the user has any enrollments + */ + boolean hasEnrollments(); +} diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java index 282261e6556f..579dfd69ec66 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java @@ -40,7 +40,8 @@ import java.util.Map; * {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/ */ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T> - extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer { + extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer, + EnrollmentModifier { private static final String TAG = "Biometrics/InternalCleanupClient"; @@ -61,6 +62,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide private final BiometricUtils<S> mBiometricUtils; private final Map<Integer, Long> mAuthenticatorIds; private final List<S> mEnrolledList; + private final boolean mHasEnrollmentsBeforeStarting; private BaseClientMonitor mCurrentTask; private final Callback mEnumerateCallback = new Callback() { @@ -115,6 +117,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide mBiometricUtils = utils; mAuthenticatorIds = authenticatorIds; mEnrolledList = enrolledList; + mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty(); } private void startCleanupUnknownHalTemplates() { @@ -166,6 +169,18 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide } @Override + public boolean hasEnrollmentStateChanged() { + final boolean hasEnrollmentsNow = !mBiometricUtils + .getBiometricsForUser(getContext(), getTargetUserId()).isEmpty(); + return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting; + } + + @Override + public boolean hasEnrollments() { + return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty(); + } + + @Override public void onEnumerationResult(BiometricAuthenticator.Identifier identifier, int remaining) { if (!(mCurrentTask instanceof InternalEnumerateClient)) { diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java index 383efce5bb2a..2a6677e55d60 100644 --- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java @@ -33,12 +33,13 @@ import java.util.Map; * A class to keep track of the remove state for a given client. */ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, T> - extends HalClientMonitor<T> implements RemovalConsumer { + extends HalClientMonitor<T> implements RemovalConsumer, EnrollmentModifier { private static final String TAG = "Biometrics/RemovalClient"; private final BiometricUtils<S> mBiometricUtils; private final Map<Integer, Long> mAuthenticatorIds; + private final boolean mHasEnrollmentsBeforeStarting; public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, @@ -49,6 +50,7 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricUtils = utils; mAuthenticatorIds = authenticatorIds; + mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty(); } @Override @@ -91,6 +93,18 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, } @Override + public boolean hasEnrollmentStateChanged() { + final boolean hasEnrollmentsNow = !mBiometricUtils + .getBiometricsForUser(getContext(), getTargetUserId()).isEmpty(); + return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting; + } + + @Override + public boolean hasEnrollments() { + return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty(); + } + + @Override public int getProtoEnum() { return BiometricsProto.CM_REMOVE; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index 0bc4f1b54d59..b2fd46d1475d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -61,10 +61,11 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId, - userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication); + userId, sensorReceiver, opPackageName, requestId, cookie, + allowBackgroundAuthentication); } @Override @@ -73,9 +74,9 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName) + public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId) throws RemoteException { - mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName); + mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, requestId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index 12d6b08b8bcf..675ee545a14f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -250,7 +250,7 @@ public class FaceService extends SystemService { } @Override // Binder call - public void authenticate(final IBinder token, final long operationId, int userId, + public long authenticate(final IBinder token, final long operationId, int userId, final IFaceServiceReceiver receiver, final String opPackageName, boolean isKeyguardBypassEnabled) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); @@ -270,38 +270,38 @@ public class FaceService extends SystemService { final Pair<Integer, ServiceProvider> provider = getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); - return; + return -1; } - provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, + return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, restricted, statsClient, isKeyguard, isKeyguardBypassEnabled); } @Override // Binder call - public void detectFace(final IBinder token, final int userId, + public long detectFace(final IBinder token, final int userId, final IFaceServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName); - return; + return -1; } if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { // If this happens, something in KeyguardUpdateMonitor is wrong. This should only // ever be invoked when the user is encrypted or lockdown. Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown"); - return; + return -1; } final Pair<Integer, ServiceProvider> provider = getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFace"); - return; + return -1; } - provider.second.scheduleFaceDetect(provider.first, token, userId, + return provider.second.scheduleFaceDetect(provider.first, token, userId, new ClientMonitorCallbackConverter(receiver), opPackageName, BiometricsProtoEnums.CLIENT_KEYGUARD); } @@ -309,8 +309,8 @@ public class FaceService extends SystemService { @Override // Binder call public void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, int userId, - IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, - boolean allowBackgroundAuthentication) { + IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId, + int cookie, boolean allowBackgroundAuthentication) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -322,9 +322,9 @@ public class FaceService extends SystemService { final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients final boolean restricted = true; // BiometricPrompt is always restricted provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, - new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, - BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication, - isKeyguardBypassEnabled); + new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId, + restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + allowBackgroundAuthentication, isKeyguardBypassEnabled); } @Override // Binder call @@ -341,7 +341,8 @@ public class FaceService extends SystemService { } @Override // Binder call - public void cancelAuthentication(final IBinder token, final String opPackageName) { + public void cancelAuthentication(final IBinder token, final String opPackageName, + final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final Pair<Integer, ServiceProvider> provider = getSingleProvider(); @@ -350,11 +351,12 @@ public class FaceService extends SystemService { return; } - provider.second.cancelAuthentication(provider.first, token); + provider.second.cancelAuthentication(provider.first, token, requestId); } @Override // Binder call - public void cancelFaceDetect(final IBinder token, final String opPackageName) { + public void cancelFaceDetect(final IBinder token, final String opPackageName, + final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "cancelFaceDetect called from non-sysui package: " @@ -368,12 +370,12 @@ public class FaceService extends SystemService { return; } - provider.second.cancelFaceDetect(provider.first, token); + provider.second.cancelFaceDetect(provider.first, token, requestId); } @Override // Binder call public void cancelAuthenticationFromService(int sensorId, final IBinder token, - final String opPackageName) { + final String opPackageName, final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -382,7 +384,7 @@ public class FaceService extends SystemService { return; } - provider.cancelAuthentication(sensorId, token); + provider.cancelAuthentication(sensorId, token, requestId); } @Override // Binder call diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java index 93ab1b65edff..e099ba372b05 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java @@ -101,18 +101,23 @@ public interface ServiceProvider { void cancelEnrollment(int sensorId, @NonNull IBinder token); - void scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, + long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient); - void cancelFaceDetect(int sensorId, @NonNull IBinder token); + void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId); - void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled); - void cancelAuthentication(int sensorId, @NonNull IBinder token); + void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled); + + void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId); void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index d66a27920f49..cbceba6cc959 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -65,7 +65,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements @FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN; FaceAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<ISession> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats, @@ -76,6 +77,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */, isKeyguardBypassEnabled); + setRequestId(requestId); mUsageStats = usageStats; mLockoutCache = lockoutCache; mNotificationManager = context.getSystemService(NotificationManager.class); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java index 1e73ac528f08..2ef0911658b1 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java @@ -43,11 +43,13 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det @Nullable private ICancellationSignal mCancellationSignal; public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull IBinder token, long requestId, + @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + setRequestId(requestId); mIsStrongBiometric = isStrongBiometric; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java index 718b9da968f5..4bae7756abe0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java @@ -65,6 +65,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; /** * Provider for a single instance of the {@link IFace} HAL. @@ -83,6 +84,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { @NonNull private final UsageStats mUsageStats; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @Nullable private IFace mDaemon; @@ -110,8 +113,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { && !client.isAlreadyDone()) { Slog.e(getTag(), "Stopping background authentication, top: " + topPackage + " currentClient: " + client); - mSensors.valueAt(i).getScheduler() - .cancelAuthenticationOrDetection(client.getToken()); + mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection( + client.getToken(), client.getRequestId()); } } } @@ -356,34 +359,39 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } @Override - public void scheduleFaceDetect(int sensorId, @NonNull IBinder token, + public long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient) { + final long id = mRequestCounter.incrementAndGet(); + mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FaceDetectClient client = new FaceDetectClient(mContext, - mSensors.get(sensorId).getLazySession(), token, callback, userId, opPackageName, + mSensors.get(sensorId).getLazySession(), + token, id, callback, userId, opPackageName, sensorId, isStrongBiometric, statsClient); scheduleForSensor(sensorId, client); }); + + return id; } @Override - public void cancelFaceDetect(int sensorId, @NonNull IBinder token) { + public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) { mHandler.post(() -> mSensors.get(sensorId).getScheduler() - .cancelAuthenticationOrDetection(token)); + .cancelAuthenticationOrDetection(token, requestId)); } @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, - @NonNull String opPackageName, boolean restricted, int statsClient, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FaceAuthenticationClient client = new FaceAuthenticationClient( - mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, - operationId, restricted, opPackageName, cookie, + mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback, + userId, operationId, restricted, opPackageName, cookie, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, mUsageStats, mSensors.get(sensorId).getLockoutCache(), allowBackgroundAuthentication, isKeyguardBypassEnabled); @@ -392,9 +400,23 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider { } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback, + opPackageName, id, restricted, statsClient, + allowBackgroundAuthentication, isKeyguardBypassEnabled); + + return id; + } + + @Override + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { mHandler.post(() -> mSensors.get(sensorId).getScheduler() - .cancelAuthenticationOrDetection(token)); + .cancelAuthenticationOrDetection(token, requestId)); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index d05333db7532..f4dcbbba21d7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -87,6 +87,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; /** * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended @@ -115,6 +116,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @NonNull private final Map<Integer, Long> mAuthenticatorIds; @Nullable private IBiometricsFace mDaemon; @NonNull private final HalResultController mHalResultController; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); private int mCurrentUserId = UserHandle.USER_NULL; private final int mSensorId; private final List<Long> mGeneratedChallengeCount = new ArrayList<>(); @@ -605,7 +608,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } @Override - public void scheduleFaceDetect(int sensorId, @NonNull IBinder token, + public long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, int statsClient) { throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" @@ -613,7 +616,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } @Override - public void cancelFaceDetect(int sensorId, @NonNull IBinder token) { + public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) { throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" + "forget to check the supportsFaceDetection flag?"); } @@ -621,26 +624,38 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, - @NonNull String opPackageName, boolean restricted, int statsClient, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId); final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext, - mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName, - cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric, - statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication, - isKeyguardBypassEnabled); + mLazyDaemon, token, requestId, receiver, userId, operationId, restricted, + opPackageName, cookie, false /* requireConfirmation */, mSensorId, + isStrongBiometric, statsClient, mLockoutTracker, mUsageStats, + allowBackgroundAuthentication, isKeyguardBypassEnabled); mScheduler.scheduleClientMonitor(client); }); } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { - mHandler.post(() -> { - mScheduler.cancelAuthenticationOrDetection(token); - }); + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver, + opPackageName, id, restricted, statsClient, + allowBackgroundAuthentication, isKeyguardBypassEnabled); + + return id; + } + + @Override + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { + mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId)); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java index 33950af2216f..40f2801541d3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java @@ -57,7 +57,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { private int mLastAcquire; FaceAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker, @@ -68,6 +69,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, isKeyguardBypassEnabled); + setRequestId(requestId); mUsageStats = usageStats; final Resources resources = getContext().getResources(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index 1e5942930b01..52d887a75216 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -61,10 +61,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId, - sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication); + sensorReceiver, opPackageName, requestId, cookie, allowBackgroundAuthentication); } @Override @@ -73,9 +73,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName) + public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId) throws RemoteException { - mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName); + mFingerprintService.cancelAuthenticationFromService( + mSensorId, token, opPackageName, requestId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 183fabdc2a7b..f35bb7ffd26b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -35,6 +35,7 @@ import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricsProtoEnums; @@ -62,11 +63,13 @@ import android.os.Build; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.util.EventLog; import android.util.Pair; @@ -111,6 +114,7 @@ public class FingerprintService extends SystemService { private final FingerprintServiceWrapper mServiceWrapper; @NonNull private final List<ServiceProvider> mServiceProviders; @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @NonNull private final Handler mHandler; @GuardedBy("mLock") @NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback> @@ -125,6 +129,37 @@ public class FingerprintService extends SystemService { */ public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) { mFingerprintStateCallback.registerFingerprintStateListener(listener); + broadcastCurrentEnrollmentState(listener); + } + + /** + * @param listener if non-null, notifies only this listener. if null, notifies all listeners + * in {@link FingerprintStateCallback}. This is slightly ugly, but reduces + * redundant code. + */ + private void broadcastCurrentEnrollmentState(@Nullable IFingerprintStateListener listener) { + final UserManager um = UserManager.get(getContext()); + synchronized (mLock) { + // Update the new listener with current state of all sensors + for (FingerprintSensorPropertiesInternal prop : mSensorProps) { + final ServiceProvider provider = getProviderForSensor(prop.sensorId); + for (UserInfo userInfo : um.getAliveUsers()) { + final boolean enrolled = !provider + .getEnrolledFingerprints(prop.sensorId, userInfo.id).isEmpty(); + + // Defer this work and allow the loop to release the lock sooner + mHandler.post(() -> { + if (listener != null) { + mFingerprintStateCallback.notifyFingerprintEnrollmentStateChanged( + listener, userInfo.id, prop.sensorId, enrolled); + } else { + mFingerprintStateCallback.notifyAllFingerprintEnrollmentStateChanged( + userInfo.id, prop.sensorId, enrolled); + } + }); + } + } + } } /** @@ -143,8 +178,7 @@ public class FingerprintService extends SystemService { return null; } - return provider.createTestSession(sensorId, callback, mFingerprintStateCallback, - opPackageName); + return provider.createTestSession(sensorId, callback, opPackageName); } @Override @@ -227,7 +261,7 @@ public class FingerprintService extends SystemService { } provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId, - receiver, opPackageName, enrollReason, mFingerprintStateCallback); + receiver, opPackageName, enrollReason); } @Override // Binder call @@ -245,7 +279,7 @@ public class FingerprintService extends SystemService { @SuppressWarnings("deprecation") @Override // Binder call - public void authenticate(final IBinder token, final long operationId, + public long authenticate(final IBinder token, final long operationId, final int sensorId, final int userId, final IFingerprintServiceReceiver receiver, final String opPackageName) { final int callingUid = Binder.getCallingUid(); @@ -255,7 +289,7 @@ public class FingerprintService extends SystemService { if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid, callingPid, callingUserId)) { Slog.w(TAG, "Authenticate rejecting package: " + opPackageName); - return; + return -1; } // Keyguard check must be done on the caller's binder identity, since it also checks @@ -270,7 +304,7 @@ public class FingerprintService extends SystemService { // SafetyNet for b/79776455 EventLog.writeEvent(0x534e4554, "79776455"); Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown"); - return; + return -1; } } finally { Binder.restoreCallingIdentity(identity); @@ -290,7 +324,7 @@ public class FingerprintService extends SystemService { } if (provider == null) { Slog.w(TAG, "Null provider for authenticate"); - return; + return -1; } final FingerprintSensorPropertiesInternal sensorProps = @@ -299,18 +333,17 @@ public class FingerprintService extends SystemService { && sensorProps != null && sensorProps.isAnyUdfpsType()) { identity = Binder.clearCallingIdentity(); try { - authenticateWithPrompt(operationId, sensorProps, userId, receiver); + return authenticateWithPrompt(operationId, sensorProps, userId, receiver); } finally { Binder.restoreCallingIdentity(identity); } - } else { - provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, - 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, - restricted, statsClient, isKeyguard, mFingerprintStateCallback); } + return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, + 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, + restricted, statsClient, isKeyguard); } - private void authenticateWithPrompt( + private long authenticateWithPrompt( final long operationId, @NonNull final FingerprintSensorPropertiesInternal props, final int userId, @@ -387,41 +420,41 @@ public class FingerprintService extends SystemService { } }; - biometricPrompt.authenticateUserForOperation( + return biometricPrompt.authenticateUserForOperation( new CancellationSignal(), executor, promptCallback, userId, operationId); } @Override - public void detectFingerprint(final IBinder token, final int userId, + public long detectFingerprint(final IBinder token, final int userId, final IFingerprintServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName); - return; + return -1; } if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { // If this happens, something in KeyguardUpdateMonitor is wrong. This should only // ever be invoked when the user is encrypted or lockdown. Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown"); - return; + return -1; } final Pair<Integer, ServiceProvider> provider = getSingleProvider(); if (provider == null) { Slog.w(TAG, "Null provider for detectFingerprint"); - return; + return -1; } - provider.second.scheduleFingerDetect(provider.first, token, userId, + return provider.second.scheduleFingerDetect(provider.first, token, userId, new ClientMonitorCallbackConverter(receiver), opPackageName, - BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback); + BiometricsProtoEnums.CLIENT_KEYGUARD); } @Override // Binder call public void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, - int cookie, boolean allowBackgroundAuthentication) { + long requestId, int cookie, boolean allowBackgroundAuthentication) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -432,9 +465,9 @@ public class FingerprintService extends SystemService { final boolean restricted = true; // BiometricPrompt is always restricted provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, - new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, - BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication, - mFingerprintStateCallback); + new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId, + restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, + allowBackgroundAuthentication); } @Override // Binder call @@ -452,7 +485,8 @@ public class FingerprintService extends SystemService { @Override // Binder call - public void cancelAuthentication(final IBinder token, final String opPackageName) { + public void cancelAuthentication(final IBinder token, final String opPackageName, + long requestId) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); @@ -469,11 +503,12 @@ public class FingerprintService extends SystemService { return; } - provider.second.cancelAuthentication(provider.first, token); + provider.second.cancelAuthentication(provider.first, token, requestId); } @Override // Binder call - public void cancelFingerprintDetect(final IBinder token, final String opPackageName) { + public void cancelFingerprintDetect(final IBinder token, final String opPackageName, + final long requestId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); if (!Utils.isKeyguard(getContext(), opPackageName)) { Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: " @@ -489,12 +524,12 @@ public class FingerprintService extends SystemService { return; } - provider.second.cancelAuthentication(provider.first, token); + provider.second.cancelAuthentication(provider.first, token, requestId); } @Override // Binder call public void cancelAuthenticationFromService(final int sensorId, final IBinder token, - final String opPackageName) { + final String opPackageName, final long requestId) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); @@ -506,7 +541,7 @@ public class FingerprintService extends SystemService { return; } - provider.cancelAuthentication(sensorId, token); + provider.cancelAuthentication(sensorId, token, requestId); } @Override // Binder call @@ -686,27 +721,6 @@ public class FingerprintService extends SystemService { .isEmpty(); } - @Override // Binder call - public boolean hasEnrolledTemplatesForAnySensor(int userId, - @NonNull List<FingerprintSensorPropertiesInternal> sensors, - @NonNull String opPackageName) { - Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - - for (FingerprintSensorPropertiesInternal prop : sensors) { - final ServiceProvider provider = getProviderForSensor(prop.sensorId); - if (provider == null) { - Slog.w(TAG, "Null provider for sensorId: " + prop.sensorId - + ", caller: " + opPackageName); - continue; - } - - if (!provider.getEnrolledFingerprints(prop.sensorId, userId).isEmpty()) { - return true; - } - } - return false; - } - public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); @@ -796,10 +810,12 @@ public class FingerprintService extends SystemService { && Settings.Secure.getIntForUser(getContext().getContentResolver(), Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, UserHandle.USER_CURRENT) != 0) { - fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor, + fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), + mFingerprintStateCallback, hidlSensor, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); } else { - fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor, + fingerprint21 = Fingerprint21.newInstance(getContext(), + mFingerprintStateCallback, hidlSensor, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); } mServiceProviders.add(fingerprint21); @@ -822,8 +838,9 @@ public class FingerprintService extends SystemService { try { final SensorProps[] props = fp.getSensorProps(); final FingerprintProvider provider = - new FingerprintProvider(getContext(), props, instance, - mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + new FingerprintProvider(getContext(), mFingerprintStateCallback, props, + instance, mLockoutResetDispatcher, + mGestureAvailabilityDispatcher); mServiceProviders.add(provider); } catch (RemoteException e) { Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); @@ -877,6 +894,7 @@ public class FingerprintService extends SystemService { } } + broadcastCurrentEnrollmentState(null); // broadcasts to all listeners broadcastAllAuthenticatorsRegistered(); }); } @@ -974,6 +992,7 @@ public class FingerprintService extends SystemService { mFingerprintStateCallback = new FingerprintStateCallback(); mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>(); mSensorProps = new ArrayList<>(); + mHandler = new Handler(Looper.getMainLooper()); } // Notifies the callbacks that all of the authenticators have been registered and removes the diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java index 5f998d81fb83..0050a895034f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java @@ -23,6 +23,7 @@ import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE; import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH; import android.annotation.NonNull; +import android.content.Context; import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintStateListener; import android.os.RemoteException; @@ -31,6 +32,9 @@ import android.util.Slog; import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AuthenticationClient; import com.android.server.biometrics.sensors.BaseClientMonitor; +import com.android.server.biometrics.sensors.EnrollClient; +import com.android.server.biometrics.sensors.EnrollmentModifier; +import com.android.server.biometrics.sensors.RemovalConsumer; import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient; import java.util.concurrent.CopyOnWriteArrayList; @@ -39,9 +43,11 @@ import java.util.concurrent.CopyOnWriteArrayList; * A callback for receiving notifications about changes in fingerprint state. */ public class FingerprintStateCallback implements BaseClientMonitor.Callback { - private @FingerprintStateListener.State int mFingerprintState; + @NonNull private final CopyOnWriteArrayList<IFingerprintStateListener> - mFingerprintStateListeners = new CopyOnWriteArrayList<>(); + mFingerprintStateListeners = new CopyOnWriteArrayList<>(); + + private @FingerprintStateListener.State int mFingerprintState; public FingerprintStateCallback() { mFingerprintState = STATE_IDLE; @@ -54,8 +60,9 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback { @Override public void onClientStarted(@NonNull BaseClientMonitor client) { final int previousFingerprintState = mFingerprintState; + if (client instanceof AuthenticationClient) { - AuthenticationClient authClient = (AuthenticationClient) client; + final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client; if (authClient.isKeyguard()) { mFingerprintState = STATE_KEYGUARD_AUTH; } else if (authClient.isBiometricPrompt()) { @@ -70,6 +77,7 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback { "Other authentication client: " + Utils.getClientName(client)); mFingerprintState = STATE_IDLE; } + Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState + " to " + mFingerprintState + ", client " + client); notifyFingerprintStateListeners(mFingerprintState); @@ -81,6 +89,18 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback { Slog.d(FingerprintService.TAG, "Client finished, fps state updated to " + mFingerprintState + ", client " + client); + + if (client instanceof EnrollmentModifier) { + EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client; + final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged(); + Slog.d(FingerprintService.TAG, "Enrollment state changed: " + enrollmentStateChanged); + if (enrollmentStateChanged) { + notifyAllFingerprintEnrollmentStateChanged(client.getTargetUserId(), + client.getSensorId(), + enrollmentModifier.hasEnrollments()); + } + } + notifyFingerprintStateListeners(mFingerprintState); } @@ -95,6 +115,32 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback { } /** + * This should be invoked when: + * 1) Enrolled --> None-enrolled + * 2) None-enrolled --> enrolled + * 3) HAL becomes ready + * 4) Listener is registered + */ + void notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId, + boolean hasEnrollments) { + for (IFingerprintStateListener listener : mFingerprintStateListeners) { + notifyFingerprintEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments); + } + } + + /** + * Notifies the listener of enrollment state changes. + */ + void notifyFingerprintEnrollmentStateChanged(@NonNull IFingerprintStateListener listener, + int userId, int sensorId, boolean hasEnrollments) { + try { + listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments); + } catch (RemoteException e) { + Slog.e(FingerprintService.TAG, "Remote exception", e); + } + } + + /** * Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward * updates in fingerprint sensor state to the SideFpNsEventHandler * @param listener diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index 706ac1013746..1772f814dd10 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -90,25 +90,27 @@ public interface ServiceProvider { */ void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFingerprintServiceReceiver receiver, - @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason, - @NonNull FingerprintStateCallback fingerprintStateCallback); + @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason); void cancelEnrollment(int sensorId, @NonNull IBinder token); - void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, + long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, - int statsClient, - @NonNull FingerprintStateCallback fingerprintStateCallback); + int statsClient); void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication); + + long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + int cookie, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, - @NonNull FingerprintStateCallback fingerprintStateCallback); + boolean allowBackgroundAuthentication); void startPreparedClient(int sensorId, int cookie); - void cancelAuthentication(int sensorId, @NonNull IBinder token); + void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId); void scheduleRemove(int sensorId, @NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId, @@ -163,6 +165,5 @@ public interface ServiceProvider { @NonNull ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, - @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull String opPackageName); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java index 29f2f20b8a75..2b50b96c69a1 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java @@ -143,8 +143,7 @@ class BiometricTestSessionImpl extends ITestSession.Stub { Utils.checkPermission(mContext, TEST_BIOMETRIC); mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, - mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL, - mFingerprintStateCallback); + mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 37ee76adeece..9d911e0a320b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -61,7 +61,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp private boolean mIsPointerDown; FingerprintAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<ISession> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @@ -74,6 +75,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */, false /* isKeyguardBypassEnabled */); + setRequestId(requestId); mLockoutCache = lockoutCache; mUdfpsOverlayController = udfpsOverlayController; mSensorProps = sensorProps; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index c5dc44988612..da91cdd981b9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -47,13 +47,15 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> implements Det @Nullable private ICancellationSignal mCancellationSignal; FingerprintDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull IBinder token, long requestId, + @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + setRequestId(requestId); mIsStrongBiometric = isStrongBiometric; mUdfpsOverlayController = udfpsOverlayController; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 102b07493134..ca83dda3bc4e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -71,6 +71,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; /** * Provider for a single instance of the {@link IFingerprint} HAL. @@ -81,6 +82,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi private boolean mTestHalEnabled; @NonNull private final Context mContext; + @NonNull private final FingerprintStateCallback mFingerprintStateCallback; @NonNull private final String mHalInstanceName; @NonNull @VisibleForTesting final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports @@ -88,6 +90,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final BiometricTaskStackListener mTaskStackListener; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @Nullable private IFingerprint mDaemon; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @@ -118,8 +122,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi && !client.isAlreadyDone()) { Slog.e(getTag(), "Stopping background authentication, top: " + topPackage + " currentClient: " + client); - mSensors.valueAt(i).getScheduler() - .cancelAuthenticationOrDetection(client.getToken()); + mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection( + client.getToken(), client.getRequestId()); } } } @@ -127,10 +131,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } } - public FingerprintProvider(@NonNull Context context, @NonNull SensorProps[] props, - @NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher, + public FingerprintProvider(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, + @NonNull SensorProps[] props, @NonNull String halInstanceName, + @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { mContext = context; + mFingerprintStateCallback = fingerprintStateCallback; mHalInstanceName = halInstanceName; mSensors = new SparseArray<>(); mHandler = new Handler(Looper.getMainLooper()); @@ -332,8 +339,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi public void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, - @FingerprintManager.EnrollReason int enrollReason, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + @FingerprintManager.EnrollReason int enrollReason) { mHandler.post(() -> { final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties() .maxEnrollmentsPerUser; @@ -347,13 +353,13 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { - fingerprintStateCallback.onClientStarted(clientMonitor); + mFingerprintStateCallback.onClientStarted(clientMonitor); } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { - fingerprintStateCallback.onClientFinished(clientMonitor, success); + mFingerprintStateCallback.onClientFinished(clientMonitor, success); if (success) { scheduleLoadAuthenticatorIdsForUser(sensorId, userId); scheduleInvalidationRequest(sensorId, userId); @@ -369,48 +375,62 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override - public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, + public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, - int statsClient, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + int statsClient) { + final long id = mRequestCounter.incrementAndGet(); mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FingerprintDetectClient client = new FingerprintDetectClient(mContext, - mSensors.get(sensorId).getLazySession(), token, callback, userId, + mSensors.get(sensorId).getLazySession(), token, id, callback, userId, opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric, statsClient); - scheduleForSensor(sensorId, client, fingerprintStateCallback); + scheduleForSensor(sensorId, client, mFingerprintStateCallback); }); + + return id; } @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, - @NonNull String opPackageName, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { mHandler.post(() -> { final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( - mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, - operationId, restricted, opPackageName, cookie, + mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback, + userId, operationId, restricted, opPackageName, cookie, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), mUdfpsOverlayController, allowBackgroundAuthentication, mSensors.get(sensorId).getSensorProperties()); - scheduleForSensor(sensorId, client, fingerprintStateCallback); + scheduleForSensor(sensorId, client, mFingerprintStateCallback); }); } @Override + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback, + opPackageName, id, restricted, statsClient, allowBackgroundAuthentication); + + return id; + } + + @Override public void startPreparedClient(int sensorId, int cookie) { mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie)); } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { mHandler.post(() -> mSensors.get(sensorId).getScheduler() - .cancelAuthenticationOrDetection(token)); + .cancelAuthenticationOrDetection(token, requestId)); } @Override @@ -444,7 +464,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId, opPackageName, FingerprintUtils.getInstance(sensorId), sensorId, mSensors.get(sensorId).getAuthenticatorIds()); - scheduleForSensor(sensorId, client); + scheduleForSensor(sensorId, client, mFingerprintStateCallback); }); } @@ -459,7 +479,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi mContext.getOpPackageName(), sensorId, enrolledList, FingerprintUtils.getInstance(sensorId), mSensors.get(sensorId).getAuthenticatorIds()); - scheduleForSensor(sensorId, client, callback); + scheduleForSensor(sensorId, client, new BaseClientMonitor.CompositeCallback(callback, + mFingerprintStateCallback)); }); } @@ -604,9 +625,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull @Override public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, - @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull String opPackageName) { - return mSensors.get(sensorId).createTestSession(callback, fingerprintStateCallback); + return mSensors.get(sensorId).createTestSession(callback, mFingerprintStateCallback); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java index c00daffb867f..79c6b1b30d5b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java @@ -143,8 +143,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub { Utils.checkPermission(mContext, TEST_BIOMETRIC); mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, - mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL, - mFingerprintStateCallback); + mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 2f5b5c7b9727..d2882aa4094c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -88,6 +88,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; /** * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or @@ -101,6 +102,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider private boolean mTestHalEnabled; final Context mContext; + @NonNull private final FingerprintStateCallback mFingerprintStateCallback; private final ActivityTaskManager mActivityTaskManager; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; private final BiometricScheduler mScheduler; @@ -115,6 +117,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @NonNull private final HalResultController mHalResultController; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @Nullable private ISidefpsController mSidefpsController; + // for requests that do not use biometric prompt + @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); private int mCurrentUserId = UserHandle.USER_NULL; private final boolean mIsUdfps; private final int mSensorId; @@ -142,7 +146,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider && !client.isAlreadyDone()) { Slog.e(TAG, "Stopping background authentication, top: " + topPackage + " currentClient: " + client); - mScheduler.cancelAuthenticationOrDetection(client.getToken()); + mScheduler.cancelAuthenticationOrDetection( + client.getToken(), client.getRequestId()); } } }); @@ -313,11 +318,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } Fingerprint21(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller) { mContext = context; + mFingerprintStateCallback = fingerprintStateCallback; mSensorProperties = sensorProps; mSensorId = sensorProps.sensorId; @@ -347,6 +354,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } public static Fingerprint21 newInstance(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @@ -358,8 +366,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider final HalResultController controller = new HalResultController(sensorProps.sensorId, context, handler, scheduler); - return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher, - controller); + return new Fingerprint21(context, fingerprintStateCallback, sensorProps, scheduler, handler, + lockoutResetDispatcher, controller); } @Override @@ -553,8 +561,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider public void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, - @FingerprintManager.EnrollReason int enrollReason, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + @FingerprintManager.EnrollReason int enrollReason) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); @@ -566,13 +573,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() { @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { - fingerprintStateCallback.onClientStarted(clientMonitor); + mFingerprintStateCallback.onClientStarted(clientMonitor); } @Override public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) { - fingerprintStateCallback.onClientFinished(clientMonitor, success); + mFingerprintStateCallback.onClientFinished(clientMonitor, success); if (success) { // Update authenticatorIds scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(), @@ -591,51 +598,65 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } @Override - public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, + public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName, - int statsClient, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + int statsClient) { + final long id = mRequestCounter.incrementAndGet(); mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); final FingerprintDetectClient client = new FingerprintDetectClient(mContext, - mLazyDaemon, token, listener, userId, opPackageName, + mLazyDaemon, token, id, listener, userId, opPackageName, mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric, statsClient); - mScheduler.scheduleClientMonitor(client, fingerprintStateCallback); + mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); }); + + return id; } @Override public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, - @NonNull String opPackageName, boolean restricted, int statsClient, - boolean allowBackgroundAuthentication, - @NonNull FingerprintStateCallback fingerprintStateCallback) { + @NonNull String opPackageName, long requestId, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( - mContext, mLazyDaemon, token, listener, userId, operationId, restricted, - opPackageName, cookie, false /* requireConfirmation */, + mContext, mLazyDaemon, token, requestId, listener, userId, operationId, + restricted, opPackageName, cookie, false /* requireConfirmation */, mSensorProperties.sensorId, isStrongBiometric, statsClient, mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, allowBackgroundAuthentication, mSensorProperties); - mScheduler.scheduleClientMonitor(client, fingerprintStateCallback); + mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); }); } @Override + public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean allowBackgroundAuthentication) { + final long id = mRequestCounter.incrementAndGet(); + + scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener, + opPackageName, id, restricted, statsClient, allowBackgroundAuthentication); + + return id; + } + + @Override public void startPreparedClient(int sensorId, int cookie) { mHandler.post(() -> mScheduler.startPreparedClient(cookie)); } @Override - public void cancelAuthentication(int sensorId, @NonNull IBinder token) { + public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId); - mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token)); + mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId)); } @Override @@ -649,7 +670,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId, userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId), mSensorProperties.sensorId, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client); + mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); }); } @@ -666,7 +687,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider 0 /* fingerprintId */, userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId), mSensorProperties.sensorId, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client); + mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback); }); } @@ -688,7 +709,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @Override public void scheduleInternalCleanup(int sensorId, int userId, @Nullable BaseClientMonitor.Callback callback) { - scheduleInternalCleanup(userId, callback); + scheduleInternalCleanup(userId, new BaseClientMonitor.CompositeCallback(callback, + mFingerprintStateCallback)); } @Override @@ -896,9 +918,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @NonNull @Override public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, - @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull String opPackageName) { return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback, - fingerprintStateCallback, this, mHalResultController); + mFingerprintStateCallback, this, mHalResultController); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index 24ce8676235a..79ad8e1a5c70 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -26,6 +26,7 @@ import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Handler; import android.os.IBinder; @@ -42,6 +43,7 @@ import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; +import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import java.util.ArrayList; @@ -270,6 +272,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @@ -280,8 +283,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher); final MockHalResultController controller = new MockHalResultController(sensorProps.sensorId, context, handler, scheduler); - return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler, - lockoutResetDispatcher, controller); + return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler, + handler, lockoutResetDispatcher, controller); } private static abstract class FakeFingerRunnable implements Runnable { @@ -400,17 +403,19 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage // internal preemption logic is not run. mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token, operationId, user, cookie, listener, opPackageName, restricted, statsClient, - isKeyguard, null /* fingerprintStateCallback */); + isKeyguard); } } private Fingerprint21UdfpsMock(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull TestableBiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull MockHalResultController controller) { - super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); + super(context, fingerprintStateCallback, sensorProps, scheduler, handler, + lockoutResetDispatcher, controller); mScheduler = scheduler; mScheduler.init(this); mHandler = handler; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index 5060744bb33e..7d95ec098fee 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -59,7 +59,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi private boolean mIsPointerDown; FingerprintAuthenticationClient(@NonNull Context context, - @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @@ -73,6 +74,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, false /* isKeyguardBypassEnabled */); + setRequestId(requestId); mLockoutFrameworkImpl = lockoutTracker; mUdfpsOverlayController = udfpsOverlayController; mSensorProps = sensorProps; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 8e73ee6b3e9f..147a20699b54 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -52,13 +52,15 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> private boolean mIsPointerDown; public FingerprintDetectClient(@NonNull Context context, - @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token, + @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, + @NonNull IBinder token, long requestId, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, int statsClient) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + setRequestId(requestId); mUdfpsOverlayController = udfpsOverlayController; mIsStrongBiometric = isStrongBiometric; } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index 491818520e3c..5c0c3626037a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -59,7 +59,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { @Override public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, - String opPackageName, int cookie, boolean allowBackgroundAuthentication) + String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication) throws RemoteException { } @@ -68,7 +68,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { } @Override - public void cancelAuthenticationFromService(IBinder token, String opPackageName) + public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId) throws RemoteException { } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 4c9d0f2691b3..2ae5cbbbf24b 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -590,7 +590,7 @@ public class DisplayDeviceConfig { newIndex = i - newStart; final float newBacklightVal; final float newNitsVal; - isLastValue = mRawBacklight[i] > mBacklightMaximum + isLastValue = mRawBacklight[i] >= mBacklightMaximum || i >= mRawBacklight.length - 1; // Clamp beginning and end to valid backlight values. if (newIndex == 0) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index afd18894f531..c2200430e53b 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -192,7 +192,9 @@ public final class DisplayManagerService extends SystemService { private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top"; private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000; - private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.1f; + // This value needs to be in sync with the threshold + // in RefreshRateConfigs::getFrameRateDivider. + private static final float THRESHOLD_FOR_REFRESH_RATES_DIVIDERS = 0.0009f; private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1; private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2; @@ -812,7 +814,7 @@ public final class DisplayManagerService extends SystemService { // Override the refresh rate only if it is a divider of the current // refresh rate. This calculation needs to be in sync with the native code - // in RefreshRateConfigs::getRefreshRateDividerForUid + // in RefreshRateConfigs::getFrameRateDivider Display.Mode currentMode = info.getMode(); float numPeriods = currentMode.getRefreshRate() / frameRateHz; float numPeriodsRound = Math.round(numPeriods); diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index d66d7ee99f2e..5797b061f2d0 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -36,9 +36,14 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.net.Uri; import android.os.Handler; +import android.os.IThermalEventListener; +import android.os.IThermalService; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; +import android.os.Temperature; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; @@ -108,6 +113,7 @@ public class DisplayModeDirector { private final UdfpsObserver mUdfpsObserver; private final SensorObserver mSensorObserver; private final HbmObserver mHbmObserver; + private final SkinThermalStatusObserver mSkinThermalStatusObserver; private final DeviceConfigInterface mDeviceConfig; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; @@ -156,6 +162,7 @@ public class DisplayModeDirector { }; mSensorObserver = new SensorObserver(context, ballotBox, injector); mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler()); + mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mDeviceConfig = injector.getDeviceConfig(); mAlwaysRespectAppRequest = false; @@ -174,6 +181,7 @@ public class DisplayModeDirector { mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); + mSkinThermalStatusObserver.observe(); synchronized (mLock) { // We may have a listener already registered before the call to start, so go ahead and // notify them to pick up our newly initialized state. @@ -606,6 +614,7 @@ public class DisplayModeDirector { mUdfpsObserver.dumpLocked(pw); mSensorObserver.dumpLocked(pw); mHbmObserver.dumpLocked(pw); + mSkinThermalStatusObserver.dumpLocked(pw); } } @@ -714,7 +723,6 @@ public class DisplayModeDirector { return mUdfpsObserver; } - @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { @@ -950,16 +958,19 @@ public class DisplayModeDirector { // user seeing the display flickering when the switches occur. public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8; + // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL. + public static final int PRIORITY_SKIN_TEMPERATURE = 9; + // High-brightness-mode may need a specific range of refresh-rates to function properly. - public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9; + public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10; // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. - public static final int PRIORITY_PROXIMITY = 10; + public static final int PRIORITY_PROXIMITY = 11; // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order // to function, so this needs to be the highest priority of all votes. - public static final int PRIORITY_UDFPS = 11; + public static final int PRIORITY_UDFPS = 12; // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString. @@ -1054,6 +1065,8 @@ public class DisplayModeDirector { return "PRIORITY_PROXIMITY"; case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; + case PRIORITY_SKIN_TEMPERATURE: + return "PRIORITY_SKIN_TEMPERATURE"; case PRIORITY_UDFPS: return "PRIORITY_UDFPS"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: @@ -2309,6 +2322,52 @@ public class DisplayModeDirector { } } + private final class SkinThermalStatusObserver extends IThermalEventListener.Stub { + private final BallotBox mBallotBox; + private final Injector mInjector; + + private @Temperature.ThrottlingStatus int mStatus = -1; + + SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) { + mInjector = injector; + mBallotBox = ballotBox; + } + + @Override + public void notifyThrottling(Temperature temp) { + mStatus = temp.getStatus(); + if (mLoggingEnabled) { + Slog.d(TAG, "New thermal throttling status " + + ", current thermal status = " + mStatus); + } + final Vote vote; + if (mStatus >= Temperature.THROTTLING_CRITICAL) { + vote = Vote.forRefreshRates(0f, 60f); + } else { + vote = null; + } + mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote); + } + + public void observe() { + IThermalService thermalService = mInjector.getThermalService(); + if (thermalService == null) { + Slog.w(TAG, "Could not observe thermal status. Service not available"); + return; + } + try { + thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register thermal status listener", e); + } + } + + void dumpLocked(PrintWriter writer) { + writer.println(" SkinThermalStatusObserver:"); + writer.println(" mStatus: " + mStatus); + } + } + private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { } @@ -2470,6 +2529,8 @@ public class DisplayModeDirector { BrightnessInfo getBrightnessInfo(int displayId); boolean isDozeState(Display d); + + IThermalService getThermalService(); } @VisibleForTesting @@ -2530,6 +2591,12 @@ public class DisplayModeDirector { return Display.isDozeState(d.getState()); } + @Override + public IThermalService getThermalService() { + return IThermalService.Stub.asInterface( + ServiceManager.getService(Context.THERMAL_SERVICE)); + } + private DisplayManager getDisplayManager() { if (mDisplayManager == null) { mDisplayManager = mContext.getSystemService(DisplayManager.class); diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index f3dcfbbf2c0a..9956da274263 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -16,6 +16,7 @@ package com.android.server.location.gnss; +import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; import static android.location.provider.ProviderProperties.ACCURACY_FINE; import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH; @@ -43,6 +44,8 @@ import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_STANDALONE; import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_RECURRENCE_PERIODIC; +import static java.lang.Math.abs; +import static java.lang.Math.max; import static java.util.concurrent.TimeUnit.MILLISECONDS; import android.app.AlarmManager; @@ -85,6 +88,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; +import android.text.format.DateUtils; import android.util.Log; import android.util.TimeUtils; @@ -103,7 +107,9 @@ import com.android.server.location.provider.AbstractLocationProvider; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -156,6 +162,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000; // Update duration extension multiplier for emergency REQUEST_LOCATION. private static final int EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER = 3; + // maximum length gnss batching may go for (1 day) + private static final int MIN_BATCH_INTERVAL_MS = (int) DateUtils.SECOND_IN_MILLIS; + private static final long MAX_BATCH_LENGTH_MS = DateUtils.DAY_IN_MILLIS; + private static final long MAX_BATCH_TIMESTAMP_DELTA_MS = 500; // Threadsafe class to hold stats reported in the Extras Bundle private static class LocationExtras { @@ -245,6 +255,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mShutdown; private boolean mStarted; private boolean mBatchingStarted; + private AlarmManager.OnAlarmListener mBatchingAlarm; private long mStartedChangedElapsedRealtime; private int mFixInterval = 1000; @@ -845,18 +856,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mFixInterval = Integer.MAX_VALUE; } - // requested batch size, or zero to disable batching - long batchSize = - mBatchingEnabled ? mProviderRequest.getMaxUpdateDelayMillis() / Math.max( - mFixInterval, 1) : 0; - if (batchSize < getBatchSize()) { - batchSize = 0; - } + int batchIntervalMs = max(mFixInterval, MIN_BATCH_INTERVAL_MS); + long batchLengthMs = Math.min(mProviderRequest.getMaxUpdateDelayMillis(), + MAX_BATCH_LENGTH_MS); // apply request to GPS engine - if (batchSize > 0) { + if (mBatchingEnabled && batchLengthMs / 2 >= batchIntervalMs) { stopNavigating(); - startBatching(); + mFixInterval = batchIntervalMs; + startBatching(batchLengthMs); } else { stopBatching(); @@ -875,7 +883,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mFixInterval >= NO_FIX_TIMEOUT) { // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT // and our fix interval is not short - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, mTimeoutListener, mHandler); } @@ -1066,7 +1074,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT // and our fix interval is not short if (mFixInterval >= NO_FIX_TIMEOUT) { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, mTimeoutListener, mHandler); } @@ -1090,12 +1098,37 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mAlarmManager.cancel(mWakeupListener); } - private void startBatching() { + private void startBatching(long batchLengthMs) { + long batchSize = batchLengthMs / mFixInterval; + if (DEBUG) { - Log.d(TAG, "startBatching " + mFixInterval); + Log.d(TAG, "startBatching " + mFixInterval + " " + batchLengthMs); } if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), true)) { mBatchingStarted = true; + + if (batchSize < getBatchSize()) { + // if the batch size is smaller than the hardware batch size, use an alarm to flush + // locations as appropriate + mBatchingAlarm = () -> { + boolean flush = false; + synchronized (mLock) { + if (mBatchingAlarm != null) { + flush = true; + mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + batchLengthMs, TAG, + mBatchingAlarm, FgThread.getHandler()); + } + } + + if (flush) { + mGnssNative.flushBatch(); + } + }; + mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + batchLengthMs, TAG, + mBatchingAlarm, FgThread.getHandler()); + } } else { Log.e(TAG, "native_start_batch failed in startBatching()"); } @@ -1104,6 +1137,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void stopBatching() { if (DEBUG) Log.d(TAG, "stopBatching"); if (mBatchingStarted) { + if (mBatchingAlarm != null) { + mAlarmManager.cancel(mBatchingAlarm); + mBatchingAlarm = null; + } mGnssNative.stopBatch(); mBatchingStarted = false; } @@ -1120,7 +1157,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // stop GPS until our next fix interval arrives stopNavigating(); long now = SystemClock.elapsedRealtime(); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, TAG, + mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, now + mFixInterval, TAG, mWakeupListener, mHandler); } @@ -1485,16 +1522,50 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.d(TAG, "Location batch of size " + locations.length + " reported"); } + if (locations.length > 0) { + // attempt to fix up timestamps if necessary + if (locations.length > 1) { + // check any realtimes outside of expected bounds + boolean fixRealtime = false; + for (int i = locations.length - 2; i >= 0; i--) { + long timeDeltaMs = locations[i + 1].getTime() - locations[i].getTime(); + long realtimeDeltaMs = locations[i + 1].getElapsedRealtimeMillis() + - locations[i].getElapsedRealtimeMillis(); + if (abs(timeDeltaMs - realtimeDeltaMs) > MAX_BATCH_TIMESTAMP_DELTA_MS) { + fixRealtime = true; + break; + } + } + + if (fixRealtime) { + // sort for monotonically increasing time before fixing realtime - realtime will + // thus also be monotonically increasing + Arrays.sort(locations, + Comparator.comparingLong(Location::getTime)); + + long expectedDeltaMs = + locations[locations.length - 1].getTime() + - locations[locations.length - 1].getElapsedRealtimeMillis(); + for (int i = locations.length - 2; i >= 0; i--) { + locations[i].setElapsedRealtimeNanos( + MILLISECONDS.toNanos( + max(locations[i].getTime() - expectedDeltaMs, 0))); + } + } else { + // sort for monotonically increasing realttime + Arrays.sort(locations, + Comparator.comparingLong(Location::getElapsedRealtimeNanos)); + } + } + + reportLocation(LocationResult.wrap(locations).validate()); + } + Runnable[] listeners; synchronized (mLock) { listeners = mFlushListeners.toArray(new Runnable[0]); mFlushListeners.clear(); } - - if (locations.length > 0) { - reportLocation(LocationResult.wrap(locations).validate()); - } - for (Runnable listener : listeners) { listener.run(); } diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 8955c288391f..62d8c320a13c 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -1078,7 +1078,7 @@ public class LocationProviderManager extends } private void onTransportFailure(Exception e) { - if (e instanceof RemoteException) { + if (e instanceof PendingIntent.CanceledException) { Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e); synchronized (mLock) { remove(); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 557fa8944445..df372b1459af 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -290,7 +290,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W combined.getValues(augmentStart, augmentEnd, entry); } - final long rawBytes = entry.rxBytes + entry.txBytes; + final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 : + (entry.rxBytes + entry.txBytes); final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes; final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes; final long targetBytes = augmentPlan.getDataUsageBytes(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b54e8f973bd6..78c909d92c58 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4363,8 +4363,7 @@ public class NotificationManagerService extends SystemService { final int userId = r.getSbn().getUserId(); if (userId != info.userid && userId != UserHandle.USER_ALL && !mUserProfiles.isCurrentProfile(userId)) { - throw new SecurityException("Disallowed call from listener: " - + info.service); + continue; } cancelNotificationFromListenerLocked(info, callingUid, callingPid, r.getSbn().getPackageName(), r.getSbn().getTag(), @@ -4431,8 +4430,7 @@ public class NotificationManagerService extends SystemService { final int userId = r.getSbn().getUserId(); if (userId != info.userid && userId != UserHandle.USER_ALL && !mUserProfiles.isCurrentProfile(userId)) { - throw new SecurityException("Disallowed call from listener: " - + info.service); + continue; } seen.add(r); if (!r.isSeen()) { @@ -7451,15 +7449,21 @@ public class NotificationManagerService extends SystemService { sentAccessibilityEvent = true; } if (DBG) Slog.v(TAG, "Interrupting!"); + boolean isInsistentUpdate = isInsistentUpdate(record); if (hasValidSound) { - if (isInCall()) { - playInCallNotification(); + if (isInsistentUpdate) { + // don't reset insistent sound, it's jarring beep = true; } else { - beep = playSound(record, soundUri); - } - if(beep) { - mSoundNotificationKey = key; + if (isInCall()) { + playInCallNotification(); + beep = true; + } else { + beep = playSound(record, soundUri); + } + if (beep) { + mSoundNotificationKey = key; + } } } @@ -7467,9 +7471,13 @@ public class NotificationManagerService extends SystemService { mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT; if (!isInCall() && hasValidVibrate && !ringerModeSilent) { - buzz = playVibration(record, vibration, hasValidSound); - if(buzz) { - mVibrateNotificationKey = key; + if (isInsistentUpdate) { + buzz = true; + } else { + buzz = playVibration(record, vibration, hasValidSound); + if (buzz) { + mVibrateNotificationKey = key; + } } } } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) { @@ -7573,6 +7581,19 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") + boolean isInsistentUpdate(final NotificationRecord record) { + return (Objects.equals(record.getKey(), mSoundNotificationKey) + || Objects.equals(record.getKey(), mVibrateNotificationKey)) + && isCurrentlyInsistent(); + } + + @GuardedBy("mNotificationLock") + boolean isCurrentlyInsistent() { + return isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey)) + || isLoopingRingtoneNotification(mNotificationsByKey.get(mVibrateNotificationKey)); + } + + @GuardedBy("mNotificationLock") boolean shouldMuteNotificationLocked(final NotificationRecord record) { // Suppressed because it's a silent update final Notification notification = record.getNotification(); @@ -7611,10 +7632,8 @@ public class NotificationManagerService extends SystemService { return true; } - // A looping ringtone, such as an incoming call is playing - if (isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey)) - || isLoopingRingtoneNotification( - mNotificationsByKey.get(mVibrateNotificationKey))) { + // A different looping ringtone, such as an incoming call is playing + if (isCurrentlyInsistent() && !isInsistentUpdate(record)) { return true; } @@ -8758,10 +8777,22 @@ public class NotificationManagerService extends SystemService { void snoozeNotificationInt(String key, long duration, String snoozeCriterionId, ManagedServiceInfo listener) { - String listenerName = listener == null ? null : listener.component.toShortString(); + if (listener == null) { + return; + } + String listenerName = listener.component.toShortString(); if ((duration <= 0 && snoozeCriterionId == null) || key == null) { return; } + synchronized (mNotificationLock) { + final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key); + if (r == null) { + return; + } + if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){ + return; + } + } if (DBG) { Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration, diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java index 7112ae16c363..628a322bf8cd 100644 --- a/services/core/java/com/android/server/notification/NotificationShellCmd.java +++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java @@ -22,6 +22,7 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.app.NotificationManager.INTERRUPTION_FILTER_UNKNOWN; +import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.INotificationManager; import android.app.Notification; @@ -44,6 +45,8 @@ import android.os.Process; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Slog; @@ -392,19 +395,28 @@ public class NotificationShellCmd extends ShellCommand { + "--context <snooze-criterion-id>) <key>"); return 1; } - if (null == mDirectService.getNotificationRecord(key)) { - pw.println("error: no notification matching key: " + key); - return 1; - } if (duration > 0 || criterion != null) { + ShellNls nls = new ShellNls(); + nls.registerAsSystemService(mDirectService.getContext(), + new ComponentName(nls.getClass().getPackageName(), + nls.getClass().getName()), + ActivityManager.getCurrentUser()); + if (!waitForBind(nls)) { + pw.println("error: could not bind a listener in time"); + return 1; + } if (duration > 0) { pw.println(String.format("snoozing <%s> until time: %s", key, new Date(System.currentTimeMillis() + duration))); + nls.snoozeNotification(key, duration); } else { pw.println(String.format("snoozing <%s> until criterion: %s", key, criterion)); + nls.snoozeNotification(key, criterion); } - mDirectService.snoozeNotificationInt(key, duration, criterion, null); + waitForSnooze(nls, key); + nls.unregisterAsSystemService(); + waitForUnbind(nls); } else { pw.println("error: invalid value for --" + subflag + ": " + flagarg); return 1; @@ -527,14 +539,17 @@ public class NotificationShellCmd extends ShellCommand { final PendingIntent pi; if ("broadcast".equals(intentKind)) { pi = PendingIntent.getBroadcastAsUser( - context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED, + context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT + | PendingIntent.FLAG_MUTABLE_UNAUDITED, UserHandle.CURRENT); } else if ("service".equals(intentKind)) { pi = PendingIntent.getService( - context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED); + context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT + | PendingIntent.FLAG_MUTABLE_UNAUDITED); } else { pi = PendingIntent.getActivityAsUser( - context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED, null, + context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT + | PendingIntent.FLAG_MUTABLE_UNAUDITED, null, UserHandle.CURRENT); } builder.setContentIntent(pi); @@ -685,9 +700,79 @@ public class NotificationShellCmd extends ShellCommand { return 0; } + private void waitForSnooze(ShellNls nls, String key) { + for (int i = 0; i < 20; i++) { + StatusBarNotification[] sbns = nls.getSnoozedNotifications(); + for (StatusBarNotification sbn : sbns) { + if (sbn.getKey().equals(key)) { + return; + } + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return; + } + + private boolean waitForBind(ShellNls nls) { + for (int i = 0; i < 20; i++) { + if (nls.isConnected) { + Slog.i(TAG, "Bound Shell NLS"); + return true; + } else { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + return false; + } + + private void waitForUnbind(ShellNls nls) { + for (int i = 0; i < 10; i++) { + if (!nls.isConnected) { + Slog.i(TAG, "Unbound Shell NLS"); + return; + } else { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + @Override public void onHelp() { getOutPrintWriter().println(USAGE); } + + @SuppressLint("OverrideAbstract") + private static class ShellNls extends NotificationListenerService { + private static ShellNls + sNotificationListenerInstance = null; + boolean isConnected; + + @Override + public void onListenerConnected() { + super.onListenerConnected(); + sNotificationListenerInstance = this; + isConnected = true; + } + @Override + public void onListenerDisconnected() { + isConnected = false; + } + + public static ShellNls getInstance() { + return sNotificationListenerInstance; + } + } } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 96bde3df1e68..e8a3a8150377 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -330,8 +330,7 @@ public class PreferencesHelper implements RankingConfig { } } - if (isShortcutOk(channel) && isDeletionOk(channel) - && !channel.isSoundMissing()) { + if (isShortcutOk(channel) && isDeletionOk(channel)) { r.channels.put(id, channel); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c4775463ee75..a0654ac0f2eb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2132,6 +2132,13 @@ public class PackageManagerService extends IPackageManager.Stub boolean filterAppAccess(String packageName, int callingUid, int userId); @LiveImplementation(override = LiveImplementation.MANDATORY) void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) + FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) + ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean debug, int userId); } /** @@ -2914,7 +2921,24 @@ public class PackageManagerService extends IPackageManager.Stub } allHomeCandidates.addAll(resolveInfos); - final String packageName = mDefaultAppProvider.getDefaultHome(userId); + String packageName = mDefaultAppProvider.getDefaultHome(userId); + if (packageName == null) { + // Role changes are not and cannot be atomic because its implementation lives inside + // a system app, so when the home role changes, there is a window when the previous + // role holder is removed and the new role holder is granted the preferred activity, + // but hasn't become the role holder yet. However, this case may be easily hit + // because the preferred activity change triggers a broadcast and receivers may try + // to get the default home activity there. So we need to fix it for this time + // window, and an easy workaround is to fallback to the current preferred activity. + final int appId = UserHandle.getAppId(Binder.getCallingUid()); + final boolean filtered = appId >= Process.FIRST_APPLICATION_UID; + FindPreferredActivityBodyResult result = findPreferredActivityInternal( + intent, null, 0, resolveInfos, true, false, false, userId, filtered); + ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo; + if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) { + packageName = preferredResolveInfo.activityInfo.packageName; + } + } if (packageName == null) { return null; } @@ -4846,6 +4870,284 @@ public class PackageManagerService extends IPackageManager.Stub } } // switch } + + // The body of findPreferredActivity. + protected FindPreferredActivityBodyResult findPreferredActivityBody( + Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult(); + + flags = updateFlagsForResolve( + flags, userId, callingUid, false /*includeInstantApps*/, + isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, + resolvedType, flags)); + intent = updateIntentForResolve(intent); + + // Try to find a matching persistent preferred activity. + result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent, + resolvedType, flags, query, debug, userId); + + // If a persistent preferred activity matched, use it. + if (result.mPreferredResolveInfo != null) { + return result; + } + + PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); + // Get the list of preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); + List<PreferredActivity> prefs = pir != null + ? pir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (prefs != null && prefs.size() > 0) { + + // First figure out how good the original match set is. + // We will only allow preferred activities that came + // from the same match quality. + int match = 0; + + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); + + final int N = query.size(); + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Match for " + ri.activityInfo + + ": 0x" + Integer.toHexString(match)); + } + if (ri.match > match) { + match = ri.match; + } + } + + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); + } + match &= IntentFilter.MATCH_CATEGORY_MASK; + final int M = prefs.size(); + for (int i = 0; i < M; i++) { + final PreferredActivity pa = prefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PreferredActivity ds=" + + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>") + + "\n component=" + pa.mPref.mComponent); + pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + if (pa.mPref.mMatch != match) { + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Skipping bad match " + + Integer.toHexString(pa.mPref.mMatch)); + } + continue; + } + // If it's not an "always" type preferred activity and that's what we're + // looking for, skip it. + if (always && !pa.mPref.mAlways) { + if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); + continue; + } + final ActivityInfo ai = getActivityInfo( + pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS + | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, + userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) + && !isDeviceProvisioned; + final boolean allowSetMutation = !excludeSetupWizardHomeActivity + && !queryMayBeFiltered; + if (ai == null) { + // Do not remove launcher's preferred activity during SetupWizard + // due to it may not install yet + if (!allowSetMutation) { + continue; + } + + // This previously registered preferred activity + // component is no longer known. Most likely an update + // to the app was installed and in the new version this + // component no longer exists. Clean it up by removing + // it from the preferred activities list, and skip it. + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + pir.removeFilter(pa); + result.mChanged = true; + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + + if (removeMatches && allowSetMutation) { + pir.removeFilter(pa); + result.mChanged = true; + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Removing match " + pa.mPref.mComponent); + } + break; + } + + // Okay we found a previously set preferred or last chosen app. + // If the result set is different from when this + // was created, and is not a subset of the preferred set, we need to + // clear it and re-ask the user their preference, if we're looking for + // an "always" type entry. + + if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { + if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { + if (allowSetMutation) { + // some components of the set are no longer present in + // the query, but the preferred activity can still be reused + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Result set changed, but PreferredActivity" + + " is still valid as only non-preferred" + + " components were removed for " + intent + + " type " + resolvedType); + } + // remove obsolete components and re-add the up-to-date + // filter + PreferredActivity freshPa = new PreferredActivity(pa, + pa.mPref.mMatch, + pa.mPref.discardObsoleteComponents(query), + pa.mPref.mComponent, + pa.mPref.mAlways); + pir.removeFilter(pa); + pir.addFilter(freshPa); + result.mChanged = true; + } else { + if (DEBUG_PREFERRED) { + Slog.i(TAG, "Do not remove preferred activity"); + } + } + } else { + if (allowSetMutation) { + Slog.i(TAG, + "Result set changed, dropping preferred activity " + + "for " + intent + " type " + + resolvedType); + if (DEBUG_PREFERRED) { + Slog.v(TAG, + "Removing preferred activity since set changed " + + pa.mPref.mComponent); + } + pir.removeFilter(pa); + // Re-add the filter as a "last chosen" entry (!always) + PreferredActivity lastChosen = new PreferredActivity( + pa, pa.mPref.mMatch, null, pa.mPref.mComponent, + false); + pir.addFilter(lastChosen); + result.mChanged = true; + } + result.mPreferredResolveInfo = null; + return result; + } + } + + // Yay! Either the set matched or we're looking for the last chosen + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + result.mPreferredResolveInfo = ri; + return result; + } + } + } + return result; + } + + public final FindPreferredActivityBodyResult findPreferredActivityInternal( + Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + + final int callingUid = Binder.getCallingUid(); + // Do NOT hold the packages lock; this calls up into the settings provider which + // could cause a deadlock. + final boolean isDeviceProvisioned = + android.provider.Settings.Global.getInt(mContext.getContentResolver(), + android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; + // Find the preferred activity - the lock is held inside the method. + return findPreferredActivityBody( + intent, resolvedType, flags, query, always, removeMatches, debug, + userId, queryMayBeFiltered, callingUid, isDeviceProvisioned); + } + + public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, + int flags, List<ResolveInfo> query, boolean debug, int userId) { + final int N = query.size(); + PersistentPreferredIntentResolver ppir = + mSettings.getPersistentPreferredActivities(userId); + // Get the list of persistent preferred activities that handle the intent + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Looking for persistent preferred activities..."); + } + List<PersistentPreferredActivity> pprefs = ppir != null + ? ppir.queryIntent(intent, resolvedType, + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, + userId) + : null; + if (pprefs != null && pprefs.size() > 0) { + final int M = pprefs.size(); + for (int i = 0; i < M; i++) { + final PersistentPreferredActivity ppa = pprefs.get(i); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Checking PersistentPreferredActivity ds=" + + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>") + + "\n component=" + ppa.mComponent); + ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } + final ActivityInfo ai = getActivityInfo(ppa.mComponent, + flags | MATCH_DISABLED_COMPONENTS, userId); + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Found persistent preferred activity:"); + if (ai != null) { + ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); + } else { + Slog.v(TAG, " null"); + } + } + if (ai == null) { + // This previously registered persistent preferred activity + // component is no longer known. Ignore it and do NOT remove it. + continue; + } + for (int j = 0; j < N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } + // Found a persistent preference that can handle the intent. + if (DEBUG_PREFERRED || debug) { + Slog.v(TAG, "Returning persistent preferred activity: " + + ri.activityInfo.packageName + "/" + ri.activityInfo.name); + } + return ri; + } + } + } + return null; + } } /** @@ -5005,6 +5307,16 @@ public class PackageManagerService extends IPackageManager.Stub super.dump(type, fd, pw, dumpState); } } + public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered, + int callingUid, boolean isDeviceProvisioned) { + synchronized (mLock) { + return super.findPreferredActivityBody(intent, resolvedType, flags, query, always, + removeMatches, debug, userId, queryMayBeFiltered, callingUid, + isDeviceProvisioned); + } + } } /** @@ -5572,6 +5884,28 @@ public class PackageManagerService extends IPackageManager.Stub current.release(); } } + public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + ThreadComputer current = live(); + try { + return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags, + query, always, removeMatches, debug, userId, queryMayBeFiltered); + } finally { + current.release(); + } + } + public final ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean debug, + int userId) { + ThreadComputer current = live(); + try { + return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType, + flags, query, debug, userId); + } finally { + current.release(); + } + } } @@ -7220,6 +7554,7 @@ public class PackageManagerService extends IPackageManager.Stub t.traceEnd(); mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); + mPermissionManager.readLegacyPermissionStateTEMP(); if (!mOnlyCore && mFirstBoot) { requestCopyPreoptedFiles(mInjector); @@ -7635,7 +7970,6 @@ public class PackageManagerService extends IPackageManager.Stub + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); - mPermissionManager.readLegacyPermissionStateTEMP(); // If the build fingerprint has changed since the last time we booted, // we need to re-grant app permission to catch any new ones that // appear. This is really a hack, and means that apps can in some @@ -9068,7 +9402,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Update given intent when being used to request {@link ResolveInfo}. */ - private Intent updateIntentForResolve(Intent intent) { + private static Intent updateIntentForResolve(Intent intent) { if (intent.getSelector() != null) { intent = intent.getSelector(); } @@ -10240,7 +10574,7 @@ public class PackageManagerService extends IPackageManager.Stub userId); // Find any earlier preferred or last chosen entries and nuke them findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, true, false, userId); + intent, resolvedType, flags, query, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivity(filter, match, null, activity, false, userId, "Setting last chosen", false); @@ -10256,7 +10590,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, false, false, userId); + intent, resolvedType, flags, query, false, false, false, userId); } private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, @@ -10298,7 +10632,7 @@ public class PackageManagerService extends IPackageManager.Stub // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType, - flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered); + flags, query, true, false, debug, userId, queryMayBeFiltered); if (ri != null) { return ri; } @@ -10411,287 +10745,72 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, + private ResolveInfo findPersistentPreferredActivityLP(Intent intent, + String resolvedType, int flags, List<ResolveInfo> query, boolean debug, int userId) { - final int N = query.size(); - PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId); - // Get the list of persistent preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities..."); - List<PersistentPreferredActivity> pprefs = ppir != null - ? ppir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (pprefs != null && pprefs.size() > 0) { - final int M = pprefs.size(); - for (int i=0; i<M; i++) { - final PersistentPreferredActivity ppa = pprefs.get(i); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Checking PersistentPreferredActivity ds=" - + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>") - + "\n component=" + ppa.mComponent); - ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - final ActivityInfo ai = getActivityInfo(ppa.mComponent, - flags | MATCH_DISABLED_COMPONENTS, userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found persistent preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - if (ai == null) { - // This previously registered persistent preferred activity - // component is no longer known. Ignore it and do NOT remove it. - continue; - } - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - // Found a persistent preference that can handle the intent. - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Returning persistent preferred activity: " + - ri.activityInfo.packageName + "/" + ri.activityInfo.name); - } - return ri; - } - } - } - return null; + return mComputer.findPersistentPreferredActivityLP(intent, + resolvedType, + flags, query, debug, userId); } - private boolean isHomeIntent(Intent intent) { + private static boolean isHomeIntent(Intent intent) { return ACTION_MAIN.equals(intent.getAction()) && intent.hasCategory(CATEGORY_HOME) && intent.hasCategory(CATEGORY_DEFAULT); } + + // findPreferredActivityBody returns two items: a "things changed" flag and a + // ResolveInfo, which is the preferred activity itself. + private static class FindPreferredActivityBodyResult { + boolean mChanged; + ResolveInfo mPreferredResolveInfo; + } + + private FindPreferredActivityBodyResult findPreferredActivityInternal( + Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, boolean always, + boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { + return mComputer.findPreferredActivityInternal( + intent, resolvedType, flags, + query, always, + removeMatches, debug, userId, queryMayBeFiltered); + } + ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List<ResolveInfo> query, int priority, boolean always, + List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug, int userId) { return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId, + intent, resolvedType, flags, query, always, removeMatches, debug, userId, UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID); } // TODO: handle preferred activities missing while user has amnesia /** <b>must not hold {@link #mLock}</b> */ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List<ResolveInfo> query, int priority, boolean always, + List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding mLock", new Throwable()); } if (!mUserManager.exists(userId)) return null; - final int callingUid = Binder.getCallingUid(); - // Do NOT hold the packages lock; this calls up into the settings provider which - // could cause a deadlock. - final boolean isDeviceProvisioned = - android.provider.Settings.Global.getInt(mContext.getContentResolver(), - android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1; - flags = updateFlagsForResolve( - flags, userId, callingUid, false /*includeInstantApps*/, - isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, - flags)); - intent = updateIntentForResolve(intent); - // writer - synchronized (mLock) { - // Try to find a matching persistent preferred activity. - ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query, - debug, userId); - // If a persistent preferred activity matched, use it. - if (pri != null) { - return pri; + FindPreferredActivityBodyResult body = findPreferredActivityInternal( + intent, resolvedType, flags, query, always, + removeMatches, debug, userId, queryMayBeFiltered); + if (body.mChanged) { + if (DEBUG_PREFERRED) { + Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); } - - PreferredIntentResolver pir = mSettings.getPreferredActivities(userId); - // Get the list of preferred activities that handle the intent - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); - List<PreferredActivity> prefs = pir != null - ? pir.queryIntent(intent, resolvedType, - (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, - userId) - : null; - if (prefs != null && prefs.size() > 0) { - boolean changed = false; - try { - // First figure out how good the original match set is. - // We will only allow preferred activities that came - // from the same match quality. - int match = 0; - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); - - final int N = query.size(); - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo - + ": 0x" + Integer.toHexString(match)); - if (ri.match > match) { - match = ri.match; - } - } - - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x" - + Integer.toHexString(match)); - - match &= IntentFilter.MATCH_CATEGORY_MASK; - final int M = prefs.size(); - for (int i=0; i<M; i++) { - final PreferredActivity pa = prefs.get(i); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Checking PreferredActivity ds=" - + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>") - + "\n component=" + pa.mPref.mComponent); - pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } - if (pa.mPref.mMatch != match) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match " - + Integer.toHexString(pa.mPref.mMatch)); - continue; - } - // If it's not an "always" type preferred activity and that's what we're - // looking for, skip it. - if (always && !pa.mPref.mAlways) { - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); - continue; - } - final ActivityInfo ai = getActivityInfo( - pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS - | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, - userId); - if (DEBUG_PREFERRED || debug) { - Slog.v(TAG, "Found preferred activity:"); - if (ai != null) { - ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); - } else { - Slog.v(TAG, " null"); - } - } - final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent) - && !isDeviceProvisioned; - final boolean allowSetMutation = !excludeSetupWizardHomeActivity - && !queryMayBeFiltered; - if (ai == null) { - // Do not remove launcher's preferred activity during SetupWizard - // due to it may not install yet - if (!allowSetMutation) { - continue; - } - - // This previously registered preferred activity - // component is no longer known. Most likely an update - // to the app was installed and in the new version this - // component no longer exists. Clean it up by removing - // it from the preferred activities list, and skip it. - Slog.w(TAG, "Removing dangling preferred activity: " - + pa.mPref.mComponent); - pir.removeFilter(pa); - changed = true; - continue; - } - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - - if (removeMatches && allowSetMutation) { - pir.removeFilter(pa); - changed = true; - if (DEBUG_PREFERRED) { - Slog.v(TAG, "Removing match " + pa.mPref.mComponent); - } - break; - } - - // Okay we found a previously set preferred or last chosen app. - // If the result set is different from when this - // was created, and is not a subset of the preferred set, we need to - // clear it and re-ask the user their preference, if we're looking for - // an "always" type entry. - - if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) { - if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) { - if (allowSetMutation) { - // some components of the set are no longer present in - // the query, but the preferred activity can still be reused - if (DEBUG_PREFERRED) { - Slog.i(TAG, "Result set changed, but PreferredActivity" - + " is still valid as only non-preferred" - + " components were removed for " + intent - + " type " + resolvedType); - } - // remove obsolete components and re-add the up-to-date - // filter - PreferredActivity freshPa = new PreferredActivity(pa, - pa.mPref.mMatch, - pa.mPref.discardObsoleteComponents(query), - pa.mPref.mComponent, - pa.mPref.mAlways); - pir.removeFilter(pa); - pir.addFilter(freshPa); - changed = true; - } else { - if (DEBUG_PREFERRED) { - Slog.i(TAG, "Do not remove preferred activity"); - } - } - } else { - if (allowSetMutation) { - Slog.i(TAG, - "Result set changed, dropping preferred activity " - + "for " + intent + " type " - + resolvedType); - if (DEBUG_PREFERRED) { - Slog.v(TAG, - "Removing preferred activity since set changed " - + pa.mPref.mComponent); - } - pir.removeFilter(pa); - // Re-add the filter as a "last chosen" entry (!always) - PreferredActivity lastChosen = new PreferredActivity( - pa, pa.mPref.mMatch, null, pa.mPref.mComponent, - false); - pir.addFilter(lastChosen); - changed = true; - } - return null; - } - } - - // Yay! Either the set matched or we're looking for the last chosen - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: " - + ri.activityInfo.packageName + "/" + ri.activityInfo.name); - return ri; - } - } - } finally { - if (changed) { - if (DEBUG_PREFERRED) { - Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); - } - scheduleWritePackageRestrictionsLocked(userId); - } - } + synchronized (mLock) { + scheduleWritePackageRestrictionsLocked(userId); } } - if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return"); - return null; + if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) { + Slog.v(TAG, "No preferred activity to return"); + } + return body.mPreferredResolveInfo; } /* @@ -23468,7 +23587,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( - intent, null, 0, resolveInfos, 0, true, false, false, userId); + intent, null, 0, resolveInfos, true, false, false, userId); final String packageName = preferredResolveInfo != null && preferredResolveInfo.activityInfo != null ? preferredResolveInfo.activityInfo.packageName : null; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index e40882268e67..b6ca67d25f77 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -484,6 +484,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidNavigationAccessibility; int mShortPressOnPowerBehavior; int mLongPressOnPowerBehavior; + long mLongPressOnPowerAssistantTimeoutMs; int mVeryLongPressOnPowerBehavior; int mDoublePressOnPowerBehavior; int mTriplePressOnPowerBehavior; @@ -732,6 +733,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Global.POWER_BUTTON_LONG_PRESS), false, this, UserHandle.USER_ALL); resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS), false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.POWER_BUTTON_VERY_LONG_PRESS), false, this, UserHandle.USER_ALL); resolver.registerContentObserver(Settings.Global.getUriFor( @@ -1732,6 +1736,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_shortPressOnPowerBehavior); mLongPressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior); + mLongPressOnPowerAssistantTimeoutMs = mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerDurationMs); mVeryLongPressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_veryLongPressOnPowerBehavior); mDoublePressOnPowerBehavior = mContext.getResources().getInteger( @@ -1955,7 +1961,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { */ private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule { PowerKeyRule(int gestures) { - super(KEYCODE_POWER, gestures); + super(mContext, KEYCODE_POWER, gestures); } @Override @@ -1970,6 +1976,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + long getLongPressTimeoutMs() { + if (getResolvedLongPressOnPowerBehavior() == LONG_PRESS_POWER_ASSISTANT) { + return mLongPressOnPowerAssistantTimeoutMs; + } else { + return super.getLongPressTimeoutMs(); + } + } + + @Override void onLongPress(long eventTime) { if (mSingleKeyGestureDetector.beganFromNonInteractive() && !mSupportLongPressPowerWhenNonInteractive) { @@ -1997,7 +2012,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { */ private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule { BackKeyRule(int gestures) { - super(KEYCODE_BACK, gestures); + super(mContext, KEYCODE_BACK, gestures); } @Override @@ -2017,7 +2032,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void initSingleKeyGestureRules() { - mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext); + mSingleKeyGestureDetector = new SingleKeyGestureDetector(); int powerKeyGestures = 0; if (hasVeryLongPressOnPowerBehavior()) { @@ -2115,6 +2130,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Global.POWER_BUTTON_LONG_PRESS, mContext.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior)); + mLongPressOnPowerAssistantTimeoutMs = Settings.Global.getLong( + mContext.getContentResolver(), + Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS, + mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerDurationMs)); mVeryLongPressOnPowerBehavior = Settings.Global.getInt(resolver, Settings.Global.POWER_BUTTON_VERY_LONG_PRESS, mContext.getResources().getInteger( @@ -5329,6 +5349,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print("mLongPressOnPowerBehavior="); pw.println(longPressOnPowerBehaviorToString(mLongPressOnPowerBehavior)); pw.print(prefix); + pw.print("mLongPressOnPowerAssistantTimeoutMs="); + pw.println(mLongPressOnPowerAssistantTimeoutMs); + pw.print(prefix); pw.print("mVeryLongPressOnPowerBehavior="); pw.println(veryLongPressOnPowerBehaviorToString(mVeryLongPressOnPowerBehavior)); pw.print(prefix); diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java index 1ef2bf9151e0..6fee69bf0472 100644 --- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java +++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java @@ -44,9 +44,6 @@ public final class SingleKeyGestureDetector { private static final int MSG_KEY_VERY_LONG_PRESS = 1; private static final int MSG_KEY_DELAYED_PRESS = 2; - private final long mLongPressTimeout; - private final long mVeryLongPressTimeout; - private volatile int mKeyPressCounter; private boolean mBeganFromNonInteractive = false; @@ -86,12 +83,19 @@ public final class SingleKeyGestureDetector { * </pre> */ abstract static class SingleKeyRule { + private final int mKeyCode; private final int mSupportedGestures; + private final long mDefaultLongPressTimeout; + private final long mDefaultVeryLongPressTimeout; - SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) { + SingleKeyRule(Context context, int keyCode, @KeyGestureFlag int supportedGestures) { mKeyCode = keyCode; mSupportedGestures = supportedGestures; + mDefaultLongPressTimeout = + ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout(); + mDefaultVeryLongPressTimeout = context.getResources().getInteger( + com.android.internal.R.integer.config_veryLongPressTimeout); } /** @@ -134,10 +138,28 @@ public final class SingleKeyGestureDetector { */ void onMultiPress(long downTime, int count) {} /** + * Returns the timeout in milliseconds for a long press. + * + * If multipress is also supported, this should always be greater than the multipress + * timeout. If very long press is supported, this should always be less than the very long + * press timeout. + */ + long getLongPressTimeoutMs() { + return mDefaultLongPressTimeout; + } + /** * Callback when long press has been detected. */ void onLongPress(long eventTime) {} /** + * Returns the timeout in milliseconds for a very long press. + * + * If long press is supported, this should always be longer than the long press timeout. + */ + long getVeryLongPressTimeoutMs() { + return mDefaultVeryLongPressTimeout; + } + /** * Callback when very long press has been detected. */ void onVeryLongPress(long eventTime) {} @@ -151,10 +173,7 @@ public final class SingleKeyGestureDetector { } } - public SingleKeyGestureDetector(Context context) { - mLongPressTimeout = ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout(); - mVeryLongPressTimeout = context.getResources().getInteger( - com.android.internal.R.integer.config_veryLongPressTimeout); + public SingleKeyGestureDetector() { mHandler = new KeyHandler(); } @@ -225,14 +244,14 @@ public final class SingleKeyGestureDetector { final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0, eventTime); msg.setAsynchronous(true); - mHandler.sendMessageDelayed(msg, mLongPressTimeout); + mHandler.sendMessageDelayed(msg, mActiveRule.getLongPressTimeoutMs()); } if (mActiveRule.supportVeryLongPress()) { final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0, eventTime); msg.setAsynchronous(true); - mHandler.sendMessageDelayed(msg, mVeryLongPressTimeout); + mHandler.sendMessageDelayed(msg, mActiveRule.getVeryLongPressTimeoutMs()); } } else { mHandler.removeMessages(MSG_KEY_LONG_PRESS); diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 7555a7f2920b..c91d8dedc41b 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -96,6 +96,7 @@ public class Notifier { private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4; private static final int MSG_PROFILE_TIMED_OUT = 5; private static final int MSG_WIRED_CHARGING_STARTED = 6; + private static final int MSG_SCREEN_POLICY = 7; private static final long[] CHARGING_VIBRATION_TIME = { 40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms @@ -120,6 +121,7 @@ public class Notifier { private final SuspendBlocker mSuspendBlocker; private final WindowManagerPolicy mPolicy; private final FaceDownDetector mFaceDownDetector; + private final ScreenUndimDetector mScreenUndimDetector; private final ActivityManagerInternal mActivityManagerInternal; private final InputManagerInternal mInputManagerInternal; private final InputMethodManagerInternal mInputMethodManagerInternal; @@ -167,13 +169,14 @@ public class Notifier { public Notifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { mContext = context; mBatteryStats = batteryStats; mAppOps = mContext.getSystemService(AppOpsManager.class); mSuspendBlocker = suspendBlocker; mPolicy = policy; mFaceDownDetector = faceDownDetector; + mScreenUndimDetector = screenUndimDetector; mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); @@ -620,6 +623,22 @@ public class Notifier { } /** + * Called when the screen policy changes. + */ + public void onScreenPolicyUpdate(int newPolicy) { + if (DEBUG) { + Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy); + } + + synchronized (mLock) { + Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY); + msg.arg1 = newPolicy; + msg.setAsynchronous(true); + mHandler.sendMessage(msg); + } + } + + /** * Dumps data for bugreports. * * @param pw The stream to print to. @@ -659,6 +678,7 @@ public class Notifier { tm.notifyUserActivity(); mPolicy.userActivity(); mFaceDownDetector.userActivity(event); + mScreenUndimDetector.userActivity(); } void postEnhancedDischargePredictionBroadcast(long delayMs) { @@ -812,6 +832,10 @@ public class Notifier { mSuspendBlocker.release(); } + private void screenPolicyChanging(int screenPolicy) { + mScreenUndimDetector.recordScreenPolicy(screenPolicy); + } + private void lockProfile(@UserIdInt int userId) { mTrustManager.setDeviceLockedForUser(userId, true /*locked*/); } @@ -852,6 +876,9 @@ public class Notifier { case MSG_WIRED_CHARGING_STARTED: showWiredChargingStarted(msg.arg1); break; + case MSG_SCREEN_POLICY: + screenPolicyChanging(msg.arg1); + break; } } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 3d47dcf4eadb..688a3b2f1d59 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -274,6 +274,7 @@ public final class PowerManagerService extends SystemService private final BatterySavingStats mBatterySavingStats; private final AttentionDetector mAttentionDetector; private final FaceDownDetector mFaceDownDetector; + private final ScreenUndimDetector mScreenUndimDetector; private final BinderService mBinderService; private final LocalService mLocalService; private final NativeWrapper mNativeWrapper; @@ -837,9 +838,10 @@ public final class PowerManagerService extends SystemService static class Injector { Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { return new Notifier( - looper, context, batteryStats, suspendBlocker, policy, faceDownDetector); + looper, context, batteryStats, suspendBlocker, policy, faceDownDetector, + screenUndimDetector); } SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) { @@ -960,6 +962,7 @@ public final class PowerManagerService extends SystemService mInjector.createAmbientDisplaySuppressionController(context); mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock); mFaceDownDetector = new FaceDownDetector(this::onFlip); + mScreenUndimDetector = new ScreenUndimDetector(); mBatterySavingStats = new BatterySavingStats(mLock); mBatterySaverPolicy = @@ -1146,7 +1149,7 @@ public final class PowerManagerService extends SystemService mBatteryStats = BatteryStatsService.getService(); mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats, mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"), - mPolicy, mFaceDownDetector); + mPolicy, mFaceDownDetector, mScreenUndimDetector); mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager, mInjector.createSuspendBlocker( @@ -1181,6 +1184,7 @@ public final class PowerManagerService extends SystemService mBatterySaverController.systemReady(); mBatterySaverPolicy.systemReady(); mFaceDownDetector.systemReady(mContext); + mScreenUndimDetector.systemReady(mContext); // Register for settings changes. resolver.registerContentObserver(Settings.Secure.getUriFor( @@ -3190,6 +3194,7 @@ public final class PowerManagerService extends SystemService final boolean ready = mDisplayManagerInternal.requestPowerState(groupId, displayPowerRequest, mRequestWaitForNegativeProximity); + mNotifier.onScreenPolicyUpdate(displayPowerRequest.policy); if (DEBUG_SPEW) { Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready diff --git a/services/core/java/com/android/server/power/ScreenUndimDetector.java b/services/core/java/com/android/server/power/ScreenUndimDetector.java new file mode 100644 index 000000000000..951bc1f76e6d --- /dev/null +++ b/services/core/java/com/android/server/power/ScreenUndimDetector.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power; + +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF; +import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.PowerManager; +import android.os.SystemClock; +import android.provider.DeviceConfig; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Detects when user manually undims the screen (x times) and acquires a wakelock to keep the screen + * on temporarily (without changing the screen timeout setting). + */ +public class ScreenUndimDetector { + private static final String TAG = "ScreenUndimDetector"; + private static final boolean DEBUG = false; + + private static final String UNDIM_DETECTOR_WAKE_LOCK = "UndimDetectorWakeLock"; + + /** DeviceConfig flag: is keep screen on feature enabled. */ + static final String KEY_KEEP_SCREEN_ON_ENABLED = "keep_screen_on_enabled"; + private static final boolean DEFAULT_KEEP_SCREEN_ON_ENABLED = true; + private static final int OUTCOME_POWER_BUTTON = + FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__POWER_BUTTON; + private static final int OUTCOME_TIMEOUT = + FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__TIMEOUT; + private boolean mKeepScreenOnEnabled; + + /** DeviceConfig flag: how long should we keep the screen on. */ + @VisibleForTesting + static final String KEY_KEEP_SCREEN_ON_FOR_MILLIS = "keep_screen_on_for_millis"; + @VisibleForTesting + static final long DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS = TimeUnit.MINUTES.toMillis(10); + private long mKeepScreenOnForMillis; + + /** DeviceConfig flag: how many user undims required to trigger keeping the screen on. */ + @VisibleForTesting + static final String KEY_UNDIMS_REQUIRED = "undims_required"; + @VisibleForTesting + static final int DEFAULT_UNDIMS_REQUIRED = 2; + private int mUndimsRequired; + + /** + * DeviceConfig flag: what is the maximum duration between undims to still consider them + * consecutive. + */ + @VisibleForTesting + static final String KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = + "max_duration_between_undims_millis"; + @VisibleForTesting + static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = TimeUnit.MINUTES.toMillis(5); + private long mMaxDurationBetweenUndimsMillis; + + @VisibleForTesting + PowerManager.WakeLock mWakeLock; + + @VisibleForTesting + int mCurrentScreenPolicy; + @VisibleForTesting + int mUndimCounter = 0; + @VisibleForTesting + long mUndimCounterStartedMillis; + private long mUndimOccurredTime = -1; + private long mInteractionAfterUndimTime = -1; + private InternalClock mClock; + + public ScreenUndimDetector() { + mClock = new InternalClock(); + } + + ScreenUndimDetector(InternalClock clock) { + mClock = clock; + } + + static class InternalClock { + public long getCurrentTime() { + return SystemClock.elapsedRealtime(); + } + } + + /** Should be called in parent's systemReady() */ + public void systemReady(Context context) { + readValuesFromDeviceConfig(); + DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE, + context.getMainExecutor(), + (properties) -> onDeviceConfigChange(properties.getKeyset())); + + final PowerManager powerManager = context.getSystemService(PowerManager.class); + mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK + | PowerManager.ON_AFTER_RELEASE, + UNDIM_DETECTOR_WAKE_LOCK); + } + + /** + * Launches a message that figures out the screen transitions and detects user undims. Must be + * called by the parent that is trying to update the screen policy. + */ + public void recordScreenPolicy(int newPolicy) { + if (newPolicy == mCurrentScreenPolicy) { + return; + } + + if (DEBUG) { + Slog.d(TAG, + "Screen policy transition: " + mCurrentScreenPolicy + " -> " + newPolicy); + } + + // update the current policy with the new one immediately so we don't accidentally get + // into a loop (which is possible if the switch below triggers a new policy). + final int currentPolicy = mCurrentScreenPolicy; + mCurrentScreenPolicy = newPolicy; + + if (!mKeepScreenOnEnabled) { + return; + } + + switch (currentPolicy) { + case POLICY_DIM: + if (newPolicy == POLICY_BRIGHT) { + final long now = mClock.getCurrentTime(); + final long timeElapsedSinceFirstUndim = now - mUndimCounterStartedMillis; + if (timeElapsedSinceFirstUndim >= mMaxDurationBetweenUndimsMillis) { + reset(); + } + if (mUndimCounter == 0) { + mUndimCounterStartedMillis = now; + } + + mUndimCounter++; + + if (DEBUG) { + Slog.d(TAG, "User undim, counter=" + mUndimCounter + + " (required=" + mUndimsRequired + ")" + + ", timeElapsedSinceFirstUndim=" + timeElapsedSinceFirstUndim + + " (max=" + mMaxDurationBetweenUndimsMillis + ")"); + } + if (mUndimCounter >= mUndimsRequired) { + reset(); + if (DEBUG) { + Slog.d(TAG, "Acquiring a wake lock for " + mKeepScreenOnForMillis); + } + if (mWakeLock != null) { + mUndimOccurredTime = mClock.getCurrentTime(); + mWakeLock.acquire(mKeepScreenOnForMillis); + } + } + } else { + if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) { + checkAndLogUndim(OUTCOME_TIMEOUT); + } + reset(); + } + break; + case POLICY_BRIGHT: + if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) { + checkAndLogUndim(OUTCOME_POWER_BUTTON); + } + if (newPolicy != POLICY_DIM) { + reset(); + } + break; + } + } + + @VisibleForTesting + void reset() { + if (DEBUG) { + Slog.d(TAG, "Resetting the undim detector"); + } + mUndimCounter = 0; + mUndimCounterStartedMillis = 0; + if (mWakeLock != null && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + + private boolean readKeepScreenOnNotificationEnabled() { + return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_KEEP_SCREEN_ON_ENABLED, + DEFAULT_KEEP_SCREEN_ON_ENABLED); + } + + private long readKeepScreenOnForMillis() { + return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_KEEP_SCREEN_ON_FOR_MILLIS, + DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS); + } + + private int readUndimsRequired() { + int undimsRequired = DeviceConfig.getInt(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + DEFAULT_UNDIMS_REQUIRED); + + if (undimsRequired < 1 || undimsRequired > 5) { + Slog.e(TAG, "Provided undimsRequired=" + undimsRequired + + " is not allowed [1, 5]; using the default=" + DEFAULT_UNDIMS_REQUIRED); + return DEFAULT_UNDIMS_REQUIRED; + } + + return undimsRequired; + } + + private long readMaxDurationBetweenUndimsMillis() { + return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS, + DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS); + } + + private void onDeviceConfigChange(@NonNull Set<String> keys) { + for (String key : keys) { + Slog.i(TAG, "onDeviceConfigChange; key=" + key); + switch (key) { + case KEY_KEEP_SCREEN_ON_ENABLED: + case KEY_KEEP_SCREEN_ON_FOR_MILLIS: + case KEY_UNDIMS_REQUIRED: + case KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS: + readValuesFromDeviceConfig(); + return; + default: + Slog.i(TAG, "Ignoring change on " + key); + } + } + } + + @VisibleForTesting + void readValuesFromDeviceConfig() { + mKeepScreenOnEnabled = readKeepScreenOnNotificationEnabled(); + mKeepScreenOnForMillis = readKeepScreenOnForMillis(); + mUndimsRequired = readUndimsRequired(); + mMaxDurationBetweenUndimsMillis = readMaxDurationBetweenUndimsMillis(); + + Slog.i(TAG, "readValuesFromDeviceConfig():" + + "\nmKeepScreenOnForMillis=" + mKeepScreenOnForMillis + + "\nmKeepScreenOnNotificationEnabled=" + mKeepScreenOnEnabled + + "\nmUndimsRequired=" + mUndimsRequired); + + } + + /** + * The user interacted with the screen after an undim, indicating the phone is in use. + * We use this event for logging. + */ + public void userActivity() { + if (mUndimOccurredTime != 1 && mInteractionAfterUndimTime == -1) { + mInteractionAfterUndimTime = mClock.getCurrentTime(); + } + } + + /** + * Checks and logs if an undim occurred. + * + * A log will occur if an undim seems to have resulted in a timeout or a direct screen off such + * as from a power button. Some outcomes may not be correctly assigned to a + * TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME value. + */ + private void checkAndLogUndim(int outcome) { + if (mUndimOccurredTime != -1) { + long now = mClock.getCurrentTime(); + FrameworkStatsLog.write(FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED, + outcome, + /* time_to_outcome_millis=*/ now - mUndimOccurredTime, + /* time_to_first_interaction_millis= */ + mInteractionAfterUndimTime != -1 ? now - mInteractionAfterUndimTime : -1 + ); + mUndimOccurredTime = -1; + mInteractionAfterUndimTime = -1; + } + } +} diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 3a7e13b8d872..abe81e139b43 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -783,13 +783,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, - int userId, String opPackageName, long operationId, + int userId, long operationId, String opPackageName, long requestId, @BiometricMultiSensorMode int multiSensorConfig) { enforceBiometricDialog(); if (mBar != null) { try { mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed, - requireConfirmation, userId, opPackageName, operationId, multiSensorConfig); + requireConfirmation, userId, operationId, opPackageName, requestId, + multiSensorConfig); } catch (RemoteException ex) { } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 771332071756..80bc16a9b052 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -16,6 +16,7 @@ package com.android.server.wallpaper; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.app.WallpaperManager.COMMAND_REAPPLY; import static android.app.WallpaperManager.FLAG_LOCK; import static android.app.WallpaperManager.FLAG_SYSTEM; @@ -2045,7 +2046,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + private boolean hasCrossUserPermission() { + final int interactPermission = + mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL); + return interactPermission == PackageManager.PERMISSION_GRANTED; + } + + @Override public boolean hasNamedWallpaper(String name) { + final int callingUser = UserHandle.getCallingUserId(); + final boolean allowCrossUser = hasCrossUserPermission(); + if (DEBUG) { + Slog.d(TAG, "hasNamedWallpaper() caller " + Binder.getCallingUid() + + " cross-user?: " + allowCrossUser); + } + synchronized (mLock) { List<UserInfo> users; final long ident = Binder.clearCallingIdentity(); @@ -2055,6 +2070,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub Binder.restoreCallingIdentity(ident); } for (UserInfo user: users) { + if (!allowCrossUser && callingUser != user.id) { + // No cross-user information for callers without permission + continue; + } + // ignore managed profiles if (user.isManagedProfile()) { continue; diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 3a4faf73bfe1..e02e8671f211 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -21,6 +21,8 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.os.Process.INVALID_UID; +import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION; import static android.view.Display.DEFAULT_DISPLAY; @@ -53,6 +55,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -64,6 +67,7 @@ import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; +import android.os.UserHandle; import android.service.voice.VoiceInteractionManagerInternal; import android.util.Slog; import android.view.RemoteAnimationDefinition; @@ -74,6 +78,7 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.protolog.common.ProtoLog; import com.android.server.LocalServices; import com.android.server.Watchdog; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.uri.NeededUriGrants; import com.android.server.vr.VrManagerInternal; @@ -557,20 +562,45 @@ class ActivityClientController extends IActivityClientController.Stub { @Override public int getLaunchedFromUid(IBinder token) { + if (!canGetLaunchedFrom()) { + return INVALID_UID; + } synchronized (mGlobalLock) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); - return r != null ? r.launchedFromUid : android.os.Process.INVALID_UID; + return r != null ? r.launchedFromUid : INVALID_UID; } } @Override public String getLaunchedFromPackage(IBinder token) { + if (!canGetLaunchedFrom()) { + return null; + } synchronized (mGlobalLock) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); return r != null ? r.launchedFromPackage : null; } } + /** Whether the caller can get the package or uid that launched its activity. */ + private boolean canGetLaunchedFrom() { + final int uid = Binder.getCallingUid(); + if (UserHandle.getAppId(uid) == SYSTEM_UID) { + return true; + } + final PackageManagerInternal pm = mService.mWindowManager.mPmInternal; + final AndroidPackage callingPkg = pm.getPackage(uid); + if (callingPkg == null) { + return false; + } + if (callingPkg.isSignedWithPlatformKey()) { + return true; + } + final String[] installerNames = pm.getKnownPackageNames( + PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.getUserId(uid)); + return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]); + } + @Override public void setRequestedOrientation(IBinder token, int requestedOrientation) { final long origId = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 308df2f4e9a0..d13c8ba96d48 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -656,6 +656,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mLastImeShown; /** + * When set to true, the IME insets will be frozen until the next app becomes IME input target. + * @see InsetsPolicy#adjustVisibilityForIme + */ + boolean mImeInsetsFrozenUntilStartInput; + + /** * A flag to determine if this AR is in the process of closing or entering PIP. This is needed * to help AR know that the app is in the process of closing but hasn't yet started closing on * the WM side. @@ -1363,6 +1369,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (newTask != null && isState(RESUMED)) { newTask.setResumedActivity(this, "onParentChanged"); + mImeInsetsFrozenUntilStartInput = false; } if (rootTask != null && rootTask.topRunningActivity() == this) { @@ -4141,7 +4148,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // The activity now gets access to the data associated with this Intent. mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants, getUriPermissionsLocked()); - final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); + final ReferrerIntent rintent = new ReferrerIntent(intent, getFilteredReferrer(referrer)); boolean unsent = true; final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping(); @@ -4759,6 +4766,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A && imeInputTarget.getWindow().mActivityRecord == this && mDisplayContent.mInputMethodWindow != null && mDisplayContent.mInputMethodWindow.isVisible(); + mImeInsetsFrozenUntilStartInput = true; } final DisplayContent displayContent = getDisplayContent(); @@ -5877,6 +5885,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // closing activity having to wait until idle timeout to be stopped or destroyed if the // next activity won't report idle (e.g. repeated view animation). mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); + + // If the activity is visible, but no windows are eligible to start input, unfreeze + // to avoid permanently frozen IME insets. + if (mImeInsetsFrozenUntilStartInput && getWindow( + win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags)) + == null) { + mImeInsetsFrozenUntilStartInput = false; + } } } @@ -7792,6 +7808,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + @Override + void onResize() { + // Reset freezing IME insets flag when the activity resized. + mImeInsetsFrozenUntilStartInput = false; + super.onResize(); + } + /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { final int orientation = getRequestedOrientation(); @@ -8482,6 +8505,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** + * Gets the referrer package name with respect to package visibility. This method returns null + * if the given package is not visible to this activity. + */ + String getFilteredReferrer(String referrerPackage) { + if (referrerPackage == null || (!referrerPackage.equals(packageName) + && mWmService.mPmInternal.filterAppAccess( + referrerPackage, info.applicationInfo.uid, mUserId))) { + return null; + } + return referrerPackage; + } + + /** * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord * should be visible depending on Keyguard state. diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index e3459a1edc0f..efa67e934543 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -848,9 +848,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // and override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, - r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(), - r.getSavedState(), r.getPersistentSavedState(), results, newIntents, - r.takeOptions(), isTransitionForward, + r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor, + proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), + results, newIntents, r.takeOptions(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken, r.getLaunchedFromBubble())); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 6892dbc158d4..9335846e7805 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3971,6 +3971,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void updateImeInputAndControlTarget(WindowState target) { if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); + if (target != null && target.mActivityRecord != null) { + target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } setImeInputTarget(target); updateImeControlTarget(); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 73d31bf7e0c8..94465ac21dff 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -355,6 +355,8 @@ public class DisplayPolicy { private PointerLocationView mPointerLocationView; + private int mDisplayCutoutTouchableRegionSize; + /** * The area covered by system windows which belong to another display. Forwarded insets is set * in case this is a virtual display, this is displayed on another display that has insets, and @@ -1081,8 +1083,21 @@ public class DisplayPolicy { (displayFrames, windowState, rect) -> { rect.bottom = rect.top + getStatusBarHeight(displayFrames); }; + final TriConsumer<DisplayFrames, WindowState, Rect> gestureFrameProvider = + (displayFrames, windowState, rect) -> { + rect.bottom = rect.top + getStatusBarHeight(displayFrames); + final DisplayCutout cutout = + displayFrames.mInsetsState.getDisplayCutout(); + if (cutout != null) { + final Rect top = cutout.getBoundingRectTop(); + if (!top.isEmpty()) { + rect.bottom = rect.bottom + mDisplayCutoutTouchableRegionSize; + } + } + }; mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider); - mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider); + mDisplayContent.setInsetProvider( + ITYPE_TOP_MANDATORY_GESTURES, win, gestureFrameProvider); mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider); break; case TYPE_NAVIGATION_BAR: @@ -1993,11 +2008,14 @@ public class DisplayPolicy { mStatusBarHeightForRotation[landscapeRotation] = mStatusBarHeightForRotation[seascapeRotation] = res.getDimensionPixelSize(R.dimen.status_bar_height_landscape); + mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize( + R.dimen.display_cutout_touchable_region_size); } else { mStatusBarHeightForRotation[portraitRotation] = mStatusBarHeightForRotation[upsideDownRotation] = mStatusBarHeightForRotation[landscapeRotation] = mStatusBarHeightForRotation[seascapeRotation] = 0; + mDisplayCutoutTouchableRegionSize = 0; } // Height of the navigation bar when presented horizontally at bottom diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 8c781a13f7db..d417d56b6d31 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -39,6 +39,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -650,6 +651,7 @@ final class InputMonitor { || type == TYPE_DOCK_DIVIDER || type == TYPE_ACCESSIBILITY_OVERLAY || type == TYPE_INPUT_CONSUMER - || type == TYPE_VOICE_INTERACTION; + || type == TYPE_VOICE_INTERACTION + || type == TYPE_STATUS_BAR_ADDITIONAL; } } diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index f2f192686ad5..a8e1c1cda72b 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -211,7 +211,7 @@ class InsetsPolicy { InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); final InsetsState state = adjustVisibilityForTransientTypes(originalState); - return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; + return adjustVisibilityForIme(target, state, state == originalState); } /** @@ -241,16 +241,37 @@ class InsetsPolicy { return state; } - // Navigation bar insets is always visible to IME. - private static InsetsState adjustVisibilityForIme(InsetsState originalState, + private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState) { - final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); - if (originalNavSource != null && !originalNavSource.isVisible()) { - final InsetsState state = copyState ? new InsetsState(originalState) : originalState; - final InsetsSource navSource = new InsetsSource(originalNavSource); - navSource.setVisible(true); - state.addSource(navSource); - return state; + if (w.mIsImWindow) { + // Navigation bar insets is always visible to IME. + final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); + if (originalNavSource != null && !originalNavSource.isVisible()) { + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource navSource = new InsetsSource(originalNavSource); + navSource.setVisible(true); + state.addSource(navSource); + return state; + } + } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) { + // During switching tasks with gestural navigation, if the IME is attached to + // one app window on that time, even the next app window is behind the IME window, + // conceptually the window should not receive the IME insets if the next window is + // not eligible IME requester and ready to show IME on top of it. + final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp(); + final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME); + + if (shouldImeAttachedToApp && originalImeSource != null) { + final boolean imeVisibility = + w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME); + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource imeSource = new InsetsSource(originalImeSource); + imeSource.setVisible(imeVisibility); + state.addSource(imeSource); + return state; + } } return originalState; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9caef70f6b51..2913e1071ed6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7070,6 +7070,7 @@ public class WindowManagerService extends IWindowManager.Stub "requestScrollCapture: caught exception dispatching to window." + "token=%s", targetWindow.mClient.asBinder()); responseBuilder.setWindowTitle(targetWindow.getName()); + responseBuilder.setPackageName(targetWindow.getOwningPackage()); responseBuilder.setDescription(String.format("caught exception: %s", e)); listener.onScrollCaptureResponse(responseBuilder.build()); } @@ -8597,8 +8598,9 @@ public class WindowManagerService extends IWindowManager.Stub if (imeTargetWindowTask == null) { return false; } - final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId, - false /* isLowResolution */); + final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId, + imeTargetWindowTask.mUserId, false /* isLowResolution */, + false /* restoreFromDisk */); return snapshot != null && snapshot.hasImeSurface(); } } diff --git a/services/tests/PackageManager/packageinstaller/Android.bp b/services/tests/PackageManager/packageinstaller/Android.bp new file mode 100644 index 000000000000..35d754b4adc5 --- /dev/null +++ b/services/tests/PackageManager/packageinstaller/Android.bp @@ -0,0 +1,39 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "PackageInstallerTests", + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + static_libs: [ + "androidx.test.rules", + "androidx.test.runner", + "junit", + "kotlin-test", + "truth-prebuilt", + ], + platform_apis: true, + test_suites: ["device-tests"], +} diff --git a/services/tests/PackageManager/packageinstaller/AndroidManifest.xml b/services/tests/PackageManager/packageinstaller/AndroidManifest.xml new file mode 100644 index 000000000000..d7062587c4bc --- /dev/null +++ b/services/tests/PackageManager/packageinstaller/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.packageinstaller.test"> + + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.packageinstaller.test" + /> + +</manifest> + diff --git a/services/tests/PackageManager/packageinstaller/AndroidTest.xml b/services/tests/PackageManager/packageinstaller/AndroidTest.xml new file mode 100644 index 000000000000..c39285ffca38 --- /dev/null +++ b/services/tests/PackageManager/packageinstaller/AndroidTest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<configuration description="Test module config for PackageInstallerTests"> + <option name="test-tag" value="PackageInstallerTests" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="PackageInstallerTests.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.packageinstaller.test" /> + </test> +</configuration> diff --git a/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt new file mode 100644 index 000000000000..d7d2726c1583 --- /dev/null +++ b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.packageinstaller.test + +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import androidx.test.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Test + +class ExportedComponentTest { + + private val context: Context = InstrumentationRegistry.getContext() + + @Test + fun verifyNoExportedReceivers() { + val intent = Intent(Intent.ACTION_INSTALL_PACKAGE).apply { + data = Uri.parse("content://mockForTest") + } + val packageInstallers = context.packageManager.queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY or PackageManager.MATCH_DISABLED_COMPONENTS) + .map { it.activityInfo.packageName } + .distinct() + .map { context.packageManager.getPackageInfo(it, PackageManager.GET_RECEIVERS) } + + assertThat(packageInstallers).isNotEmpty() + + packageInstallers.forEach { + val exported = it.receivers.filter { it.exported } + assertWithMessage("Receivers should not be exported").that(exported).isEmpty() + } + } +} diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index 17a5dccb57da..3cab5ecd3de1 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -28,6 +28,7 @@ <uses-permission android:name="android.permission.MANAGE_APPOPS"/> <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/> + <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/> diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index 4d86c8716bf1..85ef8f73534c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -182,7 +182,14 @@ public class GameManagerServiceTests { } private void mockDeviceConfigPerformance() { - String configString = "mode=2,downscaleFactor=0.5"; + String configString = "mode=2,downscaleFactor=0.5,useAngle=false"; + when(DeviceConfig.getProperty(anyString(), anyString())) + .thenReturn(configString); + } + + // ANGLE will be disabled for most apps, so treat enabling ANGLE as a special case. + private void mockDeviceConfigPerformanceEnableAngle() { + String configString = "mode=2,downscaleFactor=0.5,useAngle=true"; when(DeviceConfig.getProperty(anyString(), anyString())) .thenReturn(configString); } @@ -200,7 +207,7 @@ public class GameManagerServiceTests { } private void mockDeviceConfigInvalid() { - String configString = "mode=2,downscaleFactor=0.55"; + String configString = ""; when(DeviceConfig.getProperty(anyString(), anyString())) .thenReturn(configString); } @@ -212,7 +219,8 @@ public class GameManagerServiceTests { } private void mockGameModeOptInAll() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); @@ -224,7 +232,8 @@ public class GameManagerServiceTests { } private void mockGameModeOptInPerformance() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true); @@ -234,7 +243,8 @@ public class GameManagerServiceTests { } private void mockGameModeOptInBattery() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true); @@ -244,7 +254,8 @@ public class GameManagerServiceTests { } private void mockInterventionAllowDownscaleTrue() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, true); @@ -254,7 +265,8 @@ public class GameManagerServiceTests { } private void mockInterventionAllowDownscaleFalse() throws Exception { - final ApplicationInfo applicationInfo = new ApplicationInfo(); + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); Bundle metaDataBundle = new Bundle(); metaDataBundle.putBoolean( GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, false); @@ -263,6 +275,27 @@ public class GameManagerServiceTests { .thenReturn(applicationInfo); } + private void mockInterventionAllowAngleTrue() throws Exception { + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); + Bundle metaDataBundle = new Bundle(); + metaDataBundle.putBoolean( + GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, true); + when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); + } + + private void mockInterventionAllowAngleFalse() throws Exception { + final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser( + mPackageName, PackageManager.GET_META_DATA, USER_ID_1); + Bundle metaDataBundle = new Bundle(); + metaDataBundle.putBoolean( + GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, false); + applicationInfo.metaData = metaDataBundle; + when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); + } + /** * By default game mode is not supported. */ @@ -340,11 +373,12 @@ public class GameManagerServiceTests { */ @Test public void testSetGameModePermissionDenied() { + mockModifyGameModeGranted(); + mockDeviceConfigAll(); GameManagerService gameManagerService = new GameManagerService(mMockContext); gameManagerService.onUserStarting(USER_ID_1); // Update the game mode so we can read back something valid. - mockModifyGameModeGranted(); gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1); assertEquals(GameManager.GAME_MODE_STANDARD, gameManagerService.getGameMode(mPackageName, USER_ID_1)); @@ -427,6 +461,19 @@ public class GameManagerServiceTests { assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling); } + private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode, + boolean angleEnabled) { + gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName); + + // Validate GamePackageConfiguration returns the correct value. + GameManagerService.GamePackageConfiguration config = + gameManagerService.getConfig(mPackageName); + assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled); + + // Validate GameManagerService.getAngleEnabled() returns the correct value. + assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled); + } + /** * Phenotype device config exists, but is only propagating the default value. */ @@ -592,6 +639,50 @@ public class GameManagerServiceTests { } /** + * PERFORMANCE game mode is configured through Phenotype. The app hasn't specified any metadata. + */ + @Test + public void testInterventionAllowAngleDefault() throws Exception { + GameManagerService gameManagerService = new GameManagerService(mMockContext); + gameManagerService.onUserStarting(USER_ID_1); + mockDeviceConfigPerformance(); + mockModifyGameModeGranted(); + checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false); + } + + /** + * PERFORMANCE game mode is configured through Phenotype. The app has opted-out of ANGLE. + */ + @Test + public void testInterventionAllowAngleFalse() throws Exception { + GameManagerService gameManagerService = new GameManagerService(mMockContext); + gameManagerService.onUserStarting(USER_ID_1); + mockDeviceConfigPerformanceEnableAngle(); + mockInterventionAllowAngleFalse(); + mockModifyGameModeGranted(); + checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false); + } + + /** + * PERFORMANCE game mode is configured through Phenotype. The app has redundantly specified + * the ANGLE metadata default value of "true". + */ + @Test + public void testInterventionAllowAngleTrue() throws Exception { + mockDeviceConfigPerformanceEnableAngle(); + mockInterventionAllowAngleTrue(); + + GameManagerService gameManagerService = new GameManagerService(mMockContext); + gameManagerService.onUserStarting(USER_ID_1); + mockModifyGameModeGranted(); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1); + assertEquals(GameManager.GAME_MODE_PERFORMANCE, + gameManagerService.getGameMode(mPackageName, USER_ID_1)); + + checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, true); + } + + /** * PERFORMANCE game mode is configured through Phenotype, but the app has also opted into the * same mode. No interventions for this game mode should be available in this case. */ diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java new file mode 100644 index 000000000000..f94377fe51c2 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power; + +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR; +import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; + +import static com.android.server.power.ScreenUndimDetector.DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS; +import static com.android.server.power.ScreenUndimDetector.KEY_KEEP_SCREEN_ON_ENABLED; +import static com.android.server.power.ScreenUndimDetector.KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS; +import static com.android.server.power.ScreenUndimDetector.KEY_UNDIMS_REQUIRED; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.SystemClock; +import android.provider.DeviceConfig; +import android.testing.TestableContext; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.server.testables.TestableDeviceConfig; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.List; + +/** + * Tests for {@link com.android.server.power.ScreenUndimDetector} + */ +@RunWith(JUnit4.class) +public class ScreenUndimDetectorTest { + private static final List<Integer> ALL_POLICIES = + Arrays.asList(POLICY_OFF, + POLICY_DOZE, + POLICY_DIM, + POLICY_BRIGHT, + POLICY_VR); + + @ClassRule + public static final TestableContext sContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getTargetContext(), null); + @Rule + public TestableDeviceConfig.TestableDeviceConfigRule + mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule(); + + private ScreenUndimDetector mScreenUndimDetector; + + private final TestClock mClock = new TestClock(); + + private static class TestClock extends ScreenUndimDetector.InternalClock { + long mCurrentTime = 0; + @Override + public long getCurrentTime() { + return mCurrentTime; + } + + public void advanceTime(long millisAdvanced) { + mCurrentTime += millisAdvanced; + } + } + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(1), false /*makeDefault*/); + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS, + Long.toString(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS), + false /*makeDefault*/); + + mScreenUndimDetector = new ScreenUndimDetector(mClock); + mScreenUndimDetector.systemReady(sContext); + } + + @Test + public void recordScreenPolicy_disabledByFlag_noop() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/); + + setup(); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + + @Test + public void recordScreenPolicy_samePolicy_noop() { + for (int policy : ALL_POLICIES) { + setup(); + mScreenUndimDetector.recordScreenPolicy(policy); + mScreenUndimDetector.recordScreenPolicy(policy); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + } + + @Test + public void recordScreenPolicy_dimToBright_extends() { + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue(); + } + + @Test + public void recordScreenPolicy_otherTransitions_doesNotExtend() { + for (int from : ALL_POLICIES) { + for (int to : ALL_POLICIES) { + if (from == POLICY_DIM && to == POLICY_BRIGHT) { + continue; + } + setup(); + mScreenUndimDetector.recordScreenPolicy(from); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + } + } + } + + @Test + public void recordScreenPolicy_dimToBright_twoUndimsNeeded_extends() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue(); + } + + @Test + public void recordScreenPolicy_dimBrightDimOff_resetsCounter_doesNotExtend() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_OFF); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + } + + @Test + public void recordScreenPolicy_undimToOff_resetsCounter() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_OFF); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + } + + @Test + public void recordScreenPolicy_undimOffUndim_doesNotExtend() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + // undim + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + // off + mScreenUndimDetector.recordScreenPolicy(POLICY_OFF); + // second undim + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1); + } + + @Test + public void recordScreenPolicy_dimToBright_tooFarApart_doesNotExtend() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + mClock.advanceTime(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS + 5); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1); + } + + @Test + public void recordScreenPolicy_dimToNonBright_resets() { + for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) { + setup(); + mScreenUndimDetector.mUndimCounter = 1; + mScreenUndimDetector.mUndimCounterStartedMillis = 123; + mScreenUndimDetector.mWakeLock.acquire(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0); + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + + } + + @Test + public void recordScreenPolicy_brightToNonDim_resets() { + for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) { + setup(); + mScreenUndimDetector.mUndimCounter = 1; + mScreenUndimDetector.mUndimCounterStartedMillis = 123; + mScreenUndimDetector.mWakeLock.acquire(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0); + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + } + + @Test + public void recordScreenPolicy_otherTransitions_doesNotReset() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(3), + false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + for (int from : ALL_POLICIES) { + for (int to : ALL_POLICIES) { + if (from == POLICY_DIM && to != POLICY_BRIGHT) { + continue; + } + if (from == POLICY_BRIGHT && to != POLICY_DIM) { + continue; + } + mScreenUndimDetector.mCurrentScreenPolicy = POLICY_OFF; + mScreenUndimDetector.mUndimCounter = 1; + mScreenUndimDetector.mUndimCounterStartedMillis = + SystemClock.currentThreadTimeMillis(); + + mScreenUndimDetector.recordScreenPolicy(from); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mUndimCounter).isNotEqualTo(0); + assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isNotEqualTo(0); + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 2892bf58a7d2..b3f7587df612 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -74,6 +74,7 @@ import java.util.function.Consumer; public class AuthSessionTest { private static final String TEST_PACKAGE = "test_package"; + private static final long TEST_REQUEST_ID = 22; @Mock private Context mContext; @Mock private ITrustManager mTrustManager; @@ -112,6 +113,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, 0 /* operationId */, 0 /* userId */); @@ -133,6 +135,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, operationId, userId); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); @@ -153,6 +156,7 @@ public class AuthSessionTest { eq(userId), eq(mSensorReceiver), eq(TEST_PACKAGE), + eq(TEST_REQUEST_ID), eq(sensor.getCookie()), anyBoolean() /* allowBackgroundAuthentication */); } @@ -185,6 +189,33 @@ public class AuthSessionTest { } @Test + public void testCancelReducesAppetiteForCookies() throws Exception { + setupFace(0 /* id */, false /* confirmationAlwaysRequired */, + mock(IBiometricAuthenticator.class)); + setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); + + final AuthSession session = createAuthSession(mSensors, + false /* checkDevicePolicyManager */, + Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, + 44 /* operationId */, + 2 /* userId */); + + session.goToInitialState(); + + for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { + assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState()); + } + + session.onCancelAuthSession(false /* force */); + + for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { + session.onCookieReceived(sensor.getCookie()); + assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState()); + } + } + + @Test public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes() throws Exception { setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); @@ -212,6 +243,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, operationId, userId); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); @@ -238,7 +270,7 @@ public class AuthSessionTest { // fingerprint sensor does not start even if all cookies are received assertEquals(STATE_AUTH_STARTED, session.getState()); verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(), - anyBoolean(), anyBoolean(), anyInt(), any(), anyLong(), anyInt()); + anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong(), anyInt()); // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started. session.onDialogAnimatedIn(); @@ -277,6 +309,7 @@ public class AuthSessionTest { final AuthSession session = createAuthSession(mSensors, false /* checkDevicePolicyManager */, Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, 0 /* operationId */, 0 /* userId */); @@ -285,7 +318,8 @@ public class AuthSessionTest { sessionConsumer.accept(session); - verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE)); + verify(faceAuthenticator).cancelAuthenticationFromService( + eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID)); } private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId, @@ -302,14 +336,14 @@ public class AuthSessionTest { private AuthSession createAuthSession(List<BiometricSensor> sensors, boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, - long operationId, int userId) throws RemoteException { + long requestId, long operationId, int userId) throws RemoteException { final PromptInfo promptInfo = createPromptInfo(authenticators); final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo, checkDevicePolicyManager); return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore, - mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId, + mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, false /* debugEnabled */, mFingerprintSensorProps); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 7c7afb7dde36..69d8e89ac3b3 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -85,6 +85,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; @Presubmit @SmallTest @@ -93,6 +94,7 @@ public class BiometricServiceTest { private static final String TAG = "BiometricServiceTest"; private static final String TEST_PACKAGE_NAME = "test_package"; + private static final long TEST_REQUEST_ID = 44; private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable"; private static final String ERROR_NOT_RECOGNIZED = "not_recognized"; @@ -151,6 +153,7 @@ public class BiometricServiceTest { .thenReturn(mock(BiometricStrengthController.class)); when(mInjector.getTrustManager()).thenReturn(mTrustManager); when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager); + when(mInjector.getRequestGenerator()).thenReturn(new AtomicLong(TEST_REQUEST_ID - 1)); when(mResources.getString(R.string.biometric_error_hw_unavailable)) .thenReturn(ERROR_HW_UNAVAILABLE); @@ -215,8 +218,7 @@ public class BiometricServiceTest { mBiometricService.mCurrentAuthSession.getState()); verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl) - .cancelAuthenticationFromService(any(), - any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); // Simulate ERROR_CANCELED received from HAL mBiometricService.mBiometricSensorReceiver.onError( @@ -272,8 +274,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -357,8 +360,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, eq(false) /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -467,6 +471,7 @@ public class BiometricServiceTest { anyInt() /* userId */, any(IBiometricSensorReceiver.class), anyString() /* opPackageName */, + eq(TEST_REQUEST_ID), cookieCaptor.capture() /* cookie */, anyBoolean() /* allowBackgroundAuthentication */); @@ -488,8 +493,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); // Hardware authenticated @@ -543,8 +549,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -705,8 +712,9 @@ public class BiometricServiceTest { anyBoolean() /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, anyString(), - anyLong() /* sessionId */, + anyLong() /* requestId */, eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -805,8 +813,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -885,8 +894,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(TEST_REQUEST_ID), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -1030,8 +1040,7 @@ public class BiometricServiceTest { eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), eq(0 /* vendorCode */)); verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService( - any(), - any()); + any(), any(), anyLong()); assertNull(mBiometricService.mCurrentAuthSession); } @@ -1051,7 +1060,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mSensors.get(0).impl) - .cancelAuthenticationFromService(any(), any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); } @Test @@ -1071,7 +1080,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mSensors.get(0).impl) - .cancelAuthenticationFromService(any(), any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); } @Test @@ -1088,7 +1097,7 @@ public class BiometricServiceTest { waitForIdle(); verify(mBiometricService.mSensors.get(0).impl) - .cancelAuthenticationFromService(any(), any()); + .cancelAuthenticationFromService(any(), any(), anyLong()); verify(mReceiver1).onError( eq(BiometricAuthenticator.TYPE_FACE), eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), @@ -1126,7 +1135,7 @@ public class BiometricServiceTest { false /* requireConfirmation */, null /* authenticators */); mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken, - TEST_PACKAGE_NAME); + TEST_PACKAGE_NAME, TEST_REQUEST_ID); waitForIdle(); // Pretend that the HAL has responded to cancel with ERROR_CANCELED @@ -1353,8 +1362,8 @@ public class BiometricServiceTest { int authenticators = Authenticators.BIOMETRIC_STRONG; assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, - authenticators); + long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, authenticators); waitForIdle(); verify(mReceiver1).onError( eq(BiometricAuthenticator.TYPE_FINGERPRINT), @@ -1366,7 +1375,7 @@ public class BiometricServiceTest { authenticators = Authenticators.BIOMETRIC_WEAK; assertEquals(BiometricManager.BIOMETRIC_SUCCESS, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); @@ -1377,8 +1386,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(requestId), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); // Requesting strong and credential, when credential is setup @@ -1387,7 +1397,7 @@ public class BiometricServiceTest { when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true); assertEquals(BiometricManager.BIOMETRIC_SUCCESS, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); @@ -1399,8 +1409,9 @@ public class BiometricServiceTest { eq(true) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(requestId), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); // Un-downgrading the authenticator allows successful strong auth @@ -1414,7 +1425,7 @@ public class BiometricServiceTest { authenticators = Authenticators.BIOMETRIC_STRONG; assertEquals(BiometricManager.BIOMETRIC_SUCCESS, invokeCanAuthenticate(mBiometricService, authenticators)); - invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); verify(mBiometricService.mStatusBarService).showAuthenticationDialog( @@ -1424,8 +1435,9 @@ public class BiometricServiceTest { eq(false) /* credentialAllowed */, anyBoolean() /* requireConfirmation */, anyInt() /* userId */, + anyLong() /* operationId */, eq(TEST_PACKAGE_NAME), - anyLong() /* sessionId */, + eq(requestId), eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); } @@ -1617,11 +1629,12 @@ public class BiometricServiceTest { mBiometricService.mStatusBarService = mock(IStatusBarService.class); } - private void invokeAuthenticateAndStart(IBiometricService.Stub service, + private long invokeAuthenticateAndStart(IBiometricService.Stub service, IBiometricServiceReceiver receiver, boolean requireConfirmation, Integer authenticators) throws Exception { // Request auth, creates a pending session - invokeAuthenticate(service, receiver, requireConfirmation, authenticators); + final long requestId = invokeAuthenticate( + service, receiver, requireConfirmation, authenticators); waitForIdle(); startPendingAuthSession(mBiometricService); @@ -1629,6 +1642,8 @@ public class BiometricServiceTest { assertNotNull(mBiometricService.mCurrentAuthSession); assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); + + return requestId; } private static void startPendingAuthSession(BiometricService service) throws Exception { @@ -1644,10 +1659,10 @@ public class BiometricServiceTest { service.mImpl.onReadyForAuthentication(cookie); } - private static void invokeAuthenticate(IBiometricService.Stub service, + private static long invokeAuthenticate(IBiometricService.Stub service, IBiometricServiceReceiver receiver, boolean requireConfirmation, Integer authenticators) throws Exception { - service.authenticate( + return service.authenticate( new Binder() /* token */, 0 /* operationId */, 0 /* userId */, @@ -1657,9 +1672,9 @@ public class BiometricServiceTest { false /* checkDevicePolicy */)); } - private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service, + private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service, IBiometricServiceReceiver receiver, Integer authenticators) throws Exception { - service.authenticate( + return service.authenticate( new Binder() /* token */, 0 /* operationId */, 0 /* userId */, diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java index a41f79e8f682..e3e3900c47e0 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java @@ -40,6 +40,7 @@ import android.platform.test.annotations.Presubmit; import android.testing.TestableContext; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -193,7 +194,7 @@ public class BiometricSchedulerTest { // Request it to be canceled. The operation can be canceled immediately, and the scheduler // should go back to idle, since in this case the framework has not even requested the HAL // to authenticate yet. - mScheduler.cancelAuthenticationOrDetection(mToken); + mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */); assertNull(mScheduler.mCurrentOperation); } @@ -303,7 +304,7 @@ public class BiometricSchedulerTest { mScheduler.mPendingOperations.getFirst().mState); // Request cancel before the authentication client has started - mScheduler.cancelAuthenticationOrDetection(mToken); + mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */); waitForIdle(); assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, mScheduler.mPendingOperations.getFirst().mState); @@ -318,6 +319,107 @@ public class BiometricSchedulerTest { } @Test + public void testCancels_whenAuthRequestIdNotSet() { + testCancelsWhenRequestId(null /* requestId */, 2, true /* started */); + } + + @Test + public void testCancels_whenAuthRequestIdNotSet_notStarted() { + testCancelsWhenRequestId(null /* requestId */, 2, false /* started */); + } + + @Test + public void testCancels_whenAuthRequestIdMatches() { + testCancelsWhenRequestId(200L, 200, true /* started */); + } + + @Test + public void testCancels_whenAuthRequestIdMatches_noStarted() { + testCancelsWhenRequestId(200L, 200, false /* started */); + } + + @Test + public void testDoesNotCancel_whenAuthRequestIdMismatched() { + testCancelsWhenRequestId(10L, 20, true /* started */); + } + + @Test + public void testDoesNotCancel_whenAuthRequestIdMismatched_notStarted() { + testCancelsWhenRequestId(10L, 20, false /* started */); + } + + private void testCancelsWhenRequestId(@Nullable Long requestId, long cancelRequestId, + boolean started) { + final boolean matches = requestId == null || requestId == cancelRequestId; + final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class); + final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); + final TestAuthenticationClient client = new TestAuthenticationClient( + mContext, lazyDaemon, mToken, callback); + if (requestId != null) { + client.setRequestId(requestId); + } + + mScheduler.scheduleClientMonitor(client); + if (started) { + mScheduler.startPreparedClient(client.getCookie()); + } + waitForIdle(); + mScheduler.cancelAuthenticationOrDetection(mToken, cancelRequestId); + waitForIdle(); + + assertEquals(matches && started ? 1 : 0, client.mNumCancels); + + if (matches) { + if (started) { + assertEquals(Operation.STATE_STARTED_CANCELING, + mScheduler.mCurrentOperation.mState); + } + } else { + if (started) { + assertEquals(Operation.STATE_STARTED, + mScheduler.mCurrentOperation.mState); + } else { + assertEquals(Operation.STATE_WAITING_FOR_COOKIE, + mScheduler.mCurrentOperation.mState); + } + } + } + + @Test + public void testCancelsPending_whenAuthRequestIdsSet() { + final long requestId1 = 10; + final long requestId2 = 20; + final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class); + final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class); + final TestAuthenticationClient client1 = new TestAuthenticationClient( + mContext, lazyDaemon, mToken, callback); + client1.setRequestId(requestId1); + final TestAuthenticationClient client2 = new TestAuthenticationClient( + mContext, lazyDaemon, mToken, callback); + client2.setRequestId(requestId2); + + mScheduler.scheduleClientMonitor(client1); + mScheduler.scheduleClientMonitor(client2); + mScheduler.startPreparedClient(client1.getCookie()); + waitForIdle(); + mScheduler.cancelAuthenticationOrDetection(mToken, 9999); + waitForIdle(); + + assertEquals(Operation.STATE_STARTED, + mScheduler.mCurrentOperation.mState); + assertEquals(Operation.STATE_WAITING_IN_QUEUE, + mScheduler.mPendingOperations.getFirst().mState); + + mScheduler.cancelAuthenticationOrDetection(mToken, requestId2); + waitForIdle(); + + assertEquals(Operation.STATE_STARTED, + mScheduler.mCurrentOperation.mState); + assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, + mScheduler.mPendingOperations.getFirst().mState); + } + + @Test public void testInterruptPrecedingClients_whenExpected() { final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class, withSettings().extraInterfaces(Interruptable.class)); @@ -377,12 +479,10 @@ public class BiometricSchedulerTest { @Override protected void stopHalOperation() { - } @Override protected void startHalOperation() { - } @Override @@ -397,6 +497,7 @@ public class BiometricSchedulerTest { } private static class TestAuthenticationClient extends AuthenticationClient<Object> { + int mNumCancels = 0; public TestAuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, @@ -428,6 +529,11 @@ public class BiometricSchedulerTest { public boolean wasUserDetected() { return false; } + + public void cancel() { + mNumCancels++; + super.cancel(); + } } private static class TestClientMonitor2 extends TestClientMonitor { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java new file mode 100644 index 000000000000..09b5c5cac466 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +@Presubmit +@SmallTest +public class CompositeCallbackTest { + + @Test + public void testNullCallback() { + BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class); + BaseClientMonitor.Callback callback2 = mock(BaseClientMonitor.Callback.class); + BaseClientMonitor.Callback callback3 = null; + + BaseClientMonitor.CompositeCallback callback = new BaseClientMonitor.CompositeCallback( + callback1, callback2, callback3); + + BaseClientMonitor clientMonitor = mock(BaseClientMonitor.class); + + callback.onClientStarted(clientMonitor); + verify(callback1).onClientStarted(eq(clientMonitor)); + verify(callback2).onClientStarted(eq(clientMonitor)); + + callback.onClientFinished(clientMonitor, true /* success */); + verify(callback1).onClientFinished(eq(clientMonitor), eq(true)); + verify(callback2).onClientFinished(eq(clientMonitor), eq(true)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java new file mode 100644 index 000000000000..38e8dfa45262 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.fingerprint; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.fingerprint.FingerprintStateListener; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.server.biometrics.sensors.AuthenticationClient; +import com.android.server.biometrics.sensors.EnrollClient; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@Presubmit +@SmallTest +public class FingerprintStateCallbackTest { + + private FingerprintStateCallback mCallback; + + @Mock + FingerprintStateListener mFingerprintStateListener; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mCallback = new FingerprintStateCallback(); + mCallback.registerFingerprintStateListener(mFingerprintStateListener); + } + + @Test + public void testNoEnrollmentsToEnrollments_callbackNotified() { + testEnrollmentCallback(true /* changed */, true /* isNowEnrolled */, + true /* expectCallback */, true /* expectedCallbackValue */); + } + + @Test + public void testEnrollmentsToNoEnrollments_callbackNotified() { + testEnrollmentCallback(true /* changed */, false /* isNowEnrolled */, + true /* expectCallback */, false /* expectedCallbackValue */); + } + + @Test + public void testEnrollmentsToEnrollments_callbackNotNotified() { + testEnrollmentCallback(false /* changed */, true /* isNowEnrolled */, + false /* expectCallback */, false /* expectedCallbackValue */); + } + + private void testEnrollmentCallback(boolean changed, boolean isNowEnrolled, + boolean expectCallback, boolean expectedCallbackValue) { + EnrollClient<?> client = mock(EnrollClient.class); + + final int userId = 10; + final int sensorId = 100; + + when(client.hasEnrollmentStateChanged()).thenReturn(changed); + when(client.hasEnrollments()).thenReturn(isNowEnrolled); + when(client.getTargetUserId()).thenReturn(userId); + when(client.getSensorId()).thenReturn(sensorId); + + mCallback.onClientFinished(client, true /* success */); + if (expectCallback) { + verify(mFingerprintStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId), + eq(expectedCallbackValue)); + } else { + verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), + anyBoolean()); + } + } + + @Test + public void testAuthentication_enrollmentCallbackNeverNotified() { + AuthenticationClient<?> client = mock(AuthenticationClient.class); + mCallback.onClientFinished(client, true /* success */); + verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(), + anyBoolean()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java index 35c37efa16b4..b51918e24b13 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java @@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest; import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.HalClientMonitor; import com.android.server.biometrics.sensors.LockoutResetDispatcher; +import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import org.junit.Before; @@ -58,6 +59,8 @@ public class FingerprintProviderTest { private UserManager mUserManager; @Mock private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher; + @Mock + private FingerprintStateCallback mFingerprintStateCallback; private SensorProps[] mSensorProps; private LockoutResetDispatcher mLockoutResetDispatcher; @@ -87,8 +90,8 @@ public class FingerprintProviderTest { mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFingerprintProvider = new TestableFingerprintProvider(mContext, mSensorProps, TAG, - mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + mFingerprintProvider = new TestableFingerprintProvider(mContext, mFingerprintStateCallback, + mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); } @SuppressWarnings("rawtypes") @@ -133,11 +136,12 @@ public class FingerprintProviderTest { private static class TestableFingerprintProvider extends FingerprintProvider { public TestableFingerprintProvider(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull SensorProps[] props, @NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { - super(context, props, halInstanceName, lockoutResetDispatcher, + super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher, gestureAvailabilityDispatcher); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java index 0a0dcc97272b..f6b92097a9fb 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java @@ -41,6 +41,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.LockoutResetDispatcher; +import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; import org.junit.Before; import org.junit.Test; @@ -67,6 +68,8 @@ public class Fingerprint21Test { Fingerprint21.HalResultController mHalResultController; @Mock private BiometricScheduler mScheduler; + @Mock + private FingerprintStateCallback mFingerprintStateCallback; private LockoutResetDispatcher mLockoutResetDispatcher; private Fingerprint21 mFingerprint21; @@ -96,8 +99,9 @@ public class Fingerprint21Test { componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN, resetLockoutRequiresHardwareAuthToken); - mFingerprint21 = new TestableFingerprint21(mContext, sensorProps, mScheduler, - new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController); + mFingerprint21 = new TestableFingerprint21(mContext, mFingerprintStateCallback, sensorProps, + mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, + mHalResultController); } @Test @@ -118,11 +122,13 @@ public class Fingerprint21Test { private static class TestableFingerprint21 extends Fingerprint21 { TestableFingerprint21(@NonNull Context context, + @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller) { - super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); + super(context, fingerprintStateCallback, sensorProps, scheduler, handler, + lockoutResetDispatcher, controller); } @Override diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 1ac28abb4c2f..4564296810ff 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -56,7 +56,11 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Handler; +import android.os.IThermalEventListener; +import android.os.IThermalService; import android.os.Looper; +import android.os.RemoteException; +import android.os.Temperature; import android.provider.DeviceConfig; import android.provider.Settings; import android.test.mock.MockContentResolver; @@ -116,6 +120,8 @@ public class DisplayModeDirectorTest { public SensorManagerInternal mSensorManagerInternalMock; @Mock public DisplayManagerInternal mDisplayManagerInternalMock; + @Mock + public IThermalService mThermalServiceMock; @Before public void setUp() throws Exception { @@ -124,6 +130,7 @@ public class DisplayModeDirectorTest { final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); when(mContext.getContentResolver()).thenReturn(resolver); mInjector = spy(new FakesInjector()); + when(mInjector.getThermalService()).thenReturn(mThermalServiceMock); mHandler = new Handler(Looper.getMainLooper()); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); @@ -1547,12 +1554,52 @@ public class DisplayModeDirectorTest { assertNull(vote); } + @Test + public void testSkinTemperature() throws RemoteException { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor<IThermalEventListener> thermalEventListener = + ArgumentCaptor.forClass(IThermalEventListener.class); + + verify(mThermalServiceMock).registerThermalEventListenerWithType( + thermalEventListener.capture(), eq(Temperature.TYPE_SKIN)); + final IThermalEventListener listener = thermalEventListener.getValue(); + + // Verify that there is no skin temperature vote initially. + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); + assertNull(vote); + + // Set the skin temperature to critical and verify that we added a vote. + listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL)); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); + assertVoteForRefreshRateRange(vote, 0f, 60.f); + + // Set the skin temperature to severe and verify that the vote is gone. + listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE)); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE); + assertNull(vote); + } + + private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) { + return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status); + } + private void assertVoteForRefreshRate(Vote vote, float refreshRate) { assertThat(vote).isNotNull(); final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate); assertThat(vote.refreshRateRange).isEqualTo(expectedRange); } + private void assertVoteForRefreshRateRange( + Vote vote, float refreshRateLow, float refreshRateHigh) { + assertThat(vote).isNotNull(); + final RefreshRateRange expectedRange = + new RefreshRateRange(refreshRateLow, refreshRateHigh); + assertThat(vote.refreshRateRange).isEqualTo(expectedRange); + } + public static class FakeDeviceConfig extends FakeDeviceConfigInterface { @Override public String getProperty(String namespace, String name) { @@ -1748,6 +1795,11 @@ public class DisplayModeDirectorTest { return false; } + @Override + public IThermalService getThermalService() { + return null; + } + void notifyPeakRefreshRateChanged() { if (mPeakRefreshRateObserver != null) { mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/, diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java index 5012ca9ab420..6e3f754e4882 100644 --- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java @@ -210,7 +210,7 @@ public class NotifierTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { return mNotifierMock; } @@ -298,6 +298,7 @@ public class NotifierTest { BatteryStats.SERVICE_NAME)), mInjector.createSuspendBlocker(mService, "testBlocker"), null, + null, null); } } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 5eabc1bea148..3d64d4b5abb9 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -215,7 +215,7 @@ public class PowerManagerServiceTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { return mNotifierMock; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 71c05b5c46f7..ea46eab6e8f9 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -32,6 +32,7 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; @@ -72,6 +73,7 @@ import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Slog; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; @@ -1182,6 +1184,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mService.buzzBeepBlinkLocked(r); + verifyDelayedVibrate(mService.getVibratorHelper().createFallbackVibration(false)); // quiet update should stop making noise mService.buzzBeepBlinkLocked(s); @@ -1564,6 +1567,32 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @Test + public void testRingtoneInsistentBeep_canUpdate() throws Exception { + NotificationChannel ringtoneChannel = + new NotificationChannel("ringtone", "", IMPORTANCE_HIGH); + ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"), + new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build()); + ringtoneChannel.enableVibration(true); + NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true); + mService.addNotification(ringtoneNotification); + assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification)); + mService.buzzBeepBlinkLocked(ringtoneNotification); + verifyBeepLooped(); + verifyDelayedVibrateLooped(); + Mockito.reset(mVibrator); + Mockito.reset(mRingtonePlayer); + + assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification)); + mService.buzzBeepBlinkLocked(ringtoneNotification); + + // beep wasn't reset + verifyNeverBeep(); + verifyNeverVibrate(); + verify(mRingtonePlayer, never()).stopAsync(); + verify(mVibrator, never()).cancel(); + } + + @Test public void testCannotInterruptRingtoneInsistentBuzz() { NotificationChannel ringtoneChannel = new NotificationChannel("ringtone", "", IMPORTANCE_HIGH); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index f57c416e4a97..f660af02a0f6 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -516,7 +516,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); - mWorkerHandler = mService.new WorkerHandler(mTestableLooper.getLooper()); + mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper())); mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm, @@ -2703,6 +2703,42 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testCrossUserSnooze() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); + mService.addNotification(r); + NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); + mService.addNotification(r2); + + mListener = mock(ManagedServices.ManagedServiceInfo.class); + mListener.component = new ComponentName(PKG, PKG); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); + when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + mService.snoozeNotificationInt(r.getKey(), 1000, null, mListener); + + verify(mWorkerHandler, never()).post( + any(NotificationManagerService.SnoozeNotificationRunnable.class)); + } + + @Test + public void testSameUserSnooze() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); + mService.addNotification(r); + NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); + mService.addNotification(r2); + + mListener = mock(ManagedServices.ManagedServiceInfo.class); + mListener.component = new ComponentName(PKG, PKG); + when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); + when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + + mService.snoozeNotificationInt(r2.getKey(), 1000, null, mListener); + + verify(mWorkerHandler).post( + any(NotificationManagerService.SnoozeNotificationRunnable.class)); + } + + @Test public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception { final NotificationRecord notification = generateNotificationRecord( mTestNotificationChannel, 1, null, true); @@ -4793,6 +4829,52 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testSetNotificationsShownFromListener_protectsCrossUserInformation() + throws RemoteException { + Notification.Builder nb = new Notification.Builder( + mContext, mTestNotificationChannel.getId()) + .setContentTitle("foo") + .setSmallIcon(android.R.drawable.sym_def_app_icon); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, + nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), + null, 0); + final NotificationRecord r = + new NotificationRecord(mContext, sbn, mTestNotificationChannel); + r.setTextChanged(true); + mService.addNotification(r); + + // no security exception! + mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); + + verify(mAppUsageStats, never()).reportInterruptiveNotification( + anyString(), anyString(), anyInt()); + } + + @Test + public void testCancelNotificationsFromListener_protectsCrossUserInformation() + throws RemoteException { + Notification.Builder nb = new Notification.Builder( + mContext, mTestNotificationChannel.getId()) + .setContentTitle("foo") + .setSmallIcon(android.R.drawable.sym_def_app_icon); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, + nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), + null, 0); + final NotificationRecord r = + new NotificationRecord(mContext, sbn, mTestNotificationChannel); + r.setTextChanged(true); + mService.addNotification(r); + + // no security exception! + mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()}); + + waitForIdle(); + assertEquals(1, mService.getNotificationRecordCount()); + } + + @Test public void testMaybeRecordInterruptionLocked_doesNotRecordTwice() throws RemoteException { final NotificationRecord r = generateNotificationRecord( diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index bf0ed713e4c3..66d157708332 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -91,6 +91,7 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Settings.Secure; import android.service.notification.ConversationChannelWrapper; @@ -376,27 +377,19 @@ public class PreferencesHelperTest extends UiServiceTestCase { when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); } - private static NotificationChannel createNotificationChannel(String id, String name, - int importance) { - NotificationChannel channel = new NotificationChannel(id, name, importance); - channel.setSound(SOUND_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT); - return channel; - } - @Test public void testWriteXml_onlyBackupsTargetUser() throws Exception { // Setup package notifications. String package0 = "test.package.user0"; int uid0 = 1001; setUpPackageWithUid(package0, uid0); - NotificationChannel channel0 = createNotificationChannel("id0", "name0", IMPORTANCE_HIGH); + NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH); assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false)); String package10 = "test.package.user10"; int uid10 = 1001001; setUpPackageWithUid(package10, uid10); - NotificationChannel channel10 = createNotificationChannel("id10", "name10", - IMPORTANCE_HIGH); + NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH); assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false)); ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10); @@ -421,7 +414,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { String package0 = "test.package.user0"; int uid0 = 1001; setUpPackageWithUid(package0, uid0); - NotificationChannel channel0 = createNotificationChannel("id0", "name0", IMPORTANCE_HIGH); + NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH); assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false)); ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0); @@ -514,8 +507,9 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); NotificationChannel channel1 = - createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); - NotificationChannel channel2 = createNotificationChannel("id2", "name2", IMPORTANCE_LOW); + new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); + NotificationChannel channel2 = + new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setDescription("descriptions for all"); channel2.setSound(SOUND_URI, mAudioAttributes); channel2.enableLights(true); @@ -524,7 +518,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.enableVibration(false); channel2.setGroup(ncg.getId()); channel2.setLightColor(Color.BLUE); - NotificationChannel channel3 = createNotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); + NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); channel3.enableVibration(true); mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); @@ -631,8 +625,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test - public void testRestoreXml_withNonExistentCanonicalizedSoundUri_ignoreChannel() - throws Exception { + public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception { Thread.sleep(3000); doReturn(null) .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI)); @@ -650,7 +643,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel actualChannel = mHelper.getNotificationChannel( PKG_N_MR1, UID_N_MR1, channel.getId(), false); - assertNull(actualChannel); + assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); } @@ -659,8 +652,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { * handle its restore properly. */ @Test - public void testRestoreXml_withUncanonicalizedNonLocalSoundUri_ignoreChannel() - throws Exception { + public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception { // Not a local uncanonicalized uri, simulating that it fails to exist locally doReturn(null) .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI)); @@ -679,7 +671,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { backupWithUncanonicalizedSoundUri.getBytes(), true, UserHandle.USER_SYSTEM); NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false); - assertNull(actualChannel); + assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); } @Test @@ -703,11 +695,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); NotificationChannel channel1 = - createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); + new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel2 = - createNotificationChannel("id2", "name2", IMPORTANCE_HIGH); + new NotificationChannel("id2", "name2", IMPORTANCE_HIGH); NotificationChannel channel3 = - createNotificationChannel("id3", "name3", IMPORTANCE_LOW); + new NotificationChannel("id3", "name3", IMPORTANCE_LOW); channel3.setGroup(ncg.getId()); mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); @@ -3062,7 +3054,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testChannelXml_backupDefaultApp() throws Exception { NotificationChannel channel1 = - createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); + new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false); @@ -3343,7 +3335,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mAppOpsManager, mStatsEventBuilderFactory); mHelper.createNotificationChannel( - PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false); + PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false); assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id")); assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id")); } @@ -3354,7 +3346,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mAppOpsManager, mStatsEventBuilderFactory); mHelper.createNotificationChannel( - PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false); + PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false); mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"); NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs())); diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java index 222c692a9778..6b36fe808a2e 100644 --- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java @@ -69,7 +69,7 @@ public class SingleKeyGestureTests { @Before public void setUp() { - mDetector = new SingleKeyGestureDetector(mContext); + mDetector = new SingleKeyGestureDetector(); initSingleKeyGestureRules(); mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50; mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50; @@ -78,7 +78,7 @@ public class SingleKeyGestureTests { } private void initSingleKeyGestureRules() { - mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER, + mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(mContext, KEYCODE_POWER, KEY_LONGPRESS | KEY_VERYLONGPRESS) { @Override int getMaxMultiPressCount() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 293e862a6b74..6f04f176afd8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -39,6 +39,7 @@ import static android.os.Process.NOBODY_UID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -2816,6 +2817,73 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); } + @Test + public void testImeInsetsFrozenFlag_resetWhenReparented() { + final ActivityRecord activity = createActivityWithTask(); + final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app"); + final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow"); + final Task newTask = new TaskBuilder(mSupervisor).build(); + makeWindowVisible(app, imeWindow); + mDisplayContent.mInputMethodWindow = imeWindow; + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity is reparent to the new task. + activity.setState(RESUMED, "test"); + activity.reparent(newTask, 0 /* top */, "test"); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenResized() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + makeWindowVisibleAndDrawn(app, mImeWindow); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity is reparent to the new task. + app.mActivityRecord.onResize(); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + makeWindowVisibleAndDrawn(app, mImeWindow); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + + // Simulate app is closing and expect the last IME is shown and IME insets is frozen. + app.mActivityRecord.commitVisibility(false, false); + app.mActivityRecord.onWindowsGone(); + + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Expect IME insets frozen state will reset when the activity has no IME focusable window. + app.mActivityRecord.forAllWindowsUnchecked(w -> { + w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM; + return true; + }, true); + + app.mActivityRecord.commitVisibility(true, false); + app.mActivityRecord.onWindowsVisible(); + + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + } + private void assertHasStartingWindow(ActivityRecord atoken) { assertNotNull(atoken.mStartingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index 0d177c14427b..19f9b758811f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -30,6 +30,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -40,8 +41,10 @@ import static org.mockito.Mockito.timeout; import android.app.WaitResult; import android.content.ComponentName; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.ConditionVariable; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.Display; @@ -187,6 +190,24 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { verify(taskChangeNotifier, never()).notifyActivityDismissingDockedRootTask(); } + /** Ensures that the calling package name passed to client complies with package visibility. */ + @Test + public void testFilteredReferred() { + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setLaunchedFromPackage("other.package").setCreateTask(true).build(); + assertNotNull(activity.launchedFromPackage); + try { + mSupervisor.realStartActivityLocked(activity, activity.app, false /* andResume */, + false /* checkConfig */); + } catch (RemoteException ignored) { + } + verify(activity).getFilteredReferrer(eq(activity.launchedFromPackage)); + + activity.deliverNewIntentLocked(ActivityBuilder.DEFAULT_FAKE_UID, + new Intent(), null /* intentGrants */, "other.package2"); + verify(activity).getFilteredReferrer(eq("other.package2")); + } + /** * Ensures that notify focus task changes. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index a8e17534e6ed..8e7ba4bc3293 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -258,6 +258,7 @@ public class SystemServicesTestRule implements TestRule { final ActivityManagerInternal amInternal = mAmService.mInternal; spyOn(amInternal); doNothing().when(amInternal).trimApplications(); + doNothing().when(amInternal).scheduleAppGcs(); doNothing().when(amInternal).updateCpuStats(); doNothing().when(amInternal).updateOomAdj(); doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 92b670ed9699..d88ac256be5c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -891,6 +891,40 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); } + @Test + public void testAdjustImeInsetsVisibilityWhenSwitchingApps() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); + final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow"); + spyOn(imeWindow); + doReturn(true).when(imeWindow).isVisible(); + mDisplayContent.mInputMethodWindow = imeWindow; + + final InsetsStateController controller = mDisplayContent.getInsetsStateController(); + controller.getImeSourceProvider().setWindow(imeWindow, null, null); + + // Simulate app requests IME with updating all windows Insets State when IME is above app. + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + assertTrue(mDisplayContent.shouldImeAttachedToApp()); + controller.getImeSourceProvider().scheduleShowImePostLayout(app); + controller.getImeSourceProvider().getSource().setVisible(true); + controller.updateAboveInsetsState(imeWindow, false); + + // Expect all app windows behind IME can receive IME insets visible. + assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible()); + assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); + + // Simulate app plays closing transition to app2. + app.mActivityRecord.commitVisibility(false, false); + assertTrue(app.mActivityRecord.mLastImeShown); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Verify the IME insets is visible on app, but not for app2 during app task switching. + assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible()); + assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible()); + } + @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 588089996d6c..611b3f5e62a5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -801,6 +801,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private int mConfigChanges; private int mLaunchedFromPid; private int mLaunchedFromUid; + private String mLaunchedFromPackage; private WindowProcessController mWpc; private Bundle mIntentExtras; private boolean mOnTop = false; @@ -911,6 +912,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return this; } + ActivityBuilder setLaunchedFromPackage(String packageName) { + mLaunchedFromPackage = packageName; + return this; + } + ActivityBuilder setUseProcess(WindowProcessController wpc) { mWpc = wpc; return this; @@ -1000,6 +1006,7 @@ class WindowTestsBase extends SystemServiceTestsBase { final ActivityRecord activity = new ActivityRecord.Builder(mService) .setLaunchedFromPid(mLaunchedFromPid) .setLaunchedFromUid(mLaunchedFromUid) + .setLaunchedFromPackage(mLaunchedFromPackage) .setIntent(intent) .setActivityInfo(aInfo) .setActivityOptions(options) diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java index 7b6ccd31adcc..0c65cc40bd82 100644 --- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java +++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java @@ -45,6 +45,7 @@ import android.service.usb.UsbUidPermissionProto; import android.service.usb.UsbUserPermissionsManagerProto; import android.util.ArrayMap; import android.util.AtomicFile; +import android.util.EventLog; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.TypedXmlPullParser; @@ -74,6 +75,8 @@ class UsbUserPermissionManager { private static final String TAG = UsbUserPermissionManager.class.getSimpleName(); private static final boolean DEBUG = false; + private static final int SNET_EVENT_LOG_ID = 0x534e4554; + @GuardedBy("mLock") /** Mapping of USB device name to list of UIDs with permissions for the device * Each entry lasts until device is disconnected*/ @@ -689,8 +692,11 @@ class UsbUserPermissionManager { try { ApplicationInfo aInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0); if (aInfo.uid != uid) { - throw new IllegalArgumentException("package " + packageName + Slog.w(TAG, "package " + packageName + " does not match caller's uid " + uid); + EventLog.writeEvent(SNET_EVENT_LOG_ID, "180104273", -1, ""); + throw new IllegalArgumentException("package " + packageName + + " not found"); } } catch (PackageManager.NameNotFoundException e) { throw new IllegalArgumentException("package " + packageName + " not found"); diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index a427ed612b31..bc0a14667307 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -23,6 +23,8 @@ import android.os.Build; import android.os.Bundle; import android.util.ArrayMap; +import com.android.internal.annotations.GuardedBy; + import java.util.Collections; import java.util.List; import java.util.Map; @@ -115,6 +117,7 @@ public final class Phone { public static final int SDK_VERSION_R = 30; // A Map allows us to track each Call by its Telecom-specified call ID + @GuardedBy("mLock") private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>(); // A List allows us to keep the Calls in a stable iteration order so that casually developed @@ -139,6 +142,8 @@ public final class Phone { */ private final int mTargetSdkVersion; + private final Object mLock = new Object(); + Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) { mInCallAdapter = adapter; mCallingPackage = callingPackage; @@ -152,12 +157,16 @@ public final class Phone { return; } - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call == null) { call = new Call(this, parcelableCall.getId(), mInCallAdapter, parcelableCall.getState(), mCallingPackage, mTargetSdkVersion); - mCallByTelecomCallId.put(parcelableCall.getId(), call); - mCalls.add(call); + + synchronized (mLock) { + mCallByTelecomCallId.put(parcelableCall.getId(), call); + mCalls.add(call); + } + checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); fireCallAdded(call); @@ -169,8 +178,10 @@ public final class Phone { } final void internalRemoveCall(Call call) { - mCallByTelecomCallId.remove(call.internalGetCallId()); - mCalls.remove(call); + synchronized (mLock) { + mCallByTelecomCallId.remove(call.internalGetCallId()); + mCalls.remove(call); + } InCallService.VideoCall videoCall = call.getVideoCall(); if (videoCall != null) { @@ -183,14 +194,14 @@ public final class Phone { if (mTargetSdkVersion < SDK_VERSION_R && parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) { Log.i(this, "removing audio processing call during update for sdk compatibility"); - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call != null) { internalRemoveCall(call); } return; } - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call != null) { checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); @@ -207,8 +218,14 @@ public final class Phone { } } + Call getCallById(String callId) { + synchronized (mLock) { + return mCallByTelecomCallId.get(callId); + } + } + final void internalSetPostDialWait(String telecomId, String remaining) { - Call call = mCallByTelecomCallId.get(telecomId); + Call call = getCallById(telecomId); if (call != null) { call.internalSetPostDialWait(remaining); } @@ -222,7 +239,7 @@ public final class Phone { } final Call internalGetCallByTelecomId(String telecomId) { - return mCallByTelecomCallId.get(telecomId); + return getCallById(telecomId); } final void internalBringToForeground(boolean showDialpad) { @@ -241,35 +258,35 @@ public final class Phone { } final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) { - Call call = mCallByTelecomCallId.get(telecomId); + Call call = getCallById(telecomId); if (call != null) { call.internalOnConnectionEvent(event, extras); } } final void internalOnRttUpgradeRequest(String callId, int requestId) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnRttUpgradeRequest(requestId); } } final void internalOnRttInitiationFailure(String callId, int reason) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnRttInitiationFailure(reason); } } final void internalOnHandoverFailed(String callId, int error) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnHandoverFailed(error); } } final void internalOnHandoverComplete(String callId) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnHandoverComplete(); } diff --git a/telephony/OWNERS b/telephony/OWNERS index 4df8a4bc6413..f248fd52db83 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -8,10 +8,10 @@ rgreenwalt@google.com tgunn@google.com jminjie@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java index a1c5bbefbbe1..ae597e02f33c 100644 --- a/telephony/java/android/telephony/AvailableNetworkInfo.java +++ b/telephony/java/android/telephony/AvailableNetworkInfo.java @@ -19,6 +19,7 @@ package android.telephony; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.RadioAccessSpecifier; import java.util.ArrayList; import java.util.Arrays; @@ -76,13 +77,28 @@ public final class AvailableNetworkInfo implements Parcelable { * Opportunistic network service will use these bands to scan. * * When no specific bands are specified (empty array or null) CBRS band - * {@link AccessNetworkConstants.EutranBand.BAND_48} will be used for network scan. + * {@link AccessNetworkConstants.EutranBand.BAND_48 + * } will be used for network scan. * * See {@link AccessNetworkConstants} for details. + * + * @deprecated use {@link #mRadioAccessSpecifiers} instead */ + @Deprecated private ArrayList<Integer> mBands; /** + * Returns a list of {@link RadioAccessSpecifier} associated with the available network. + * Opportunistic network service will use this to determine which bands to scan for. + * + * If this entry is left empty, {@link RadioAcccessSpecifier}s with {@link AccessNetworkType}s + * of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link + * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed + * by Opportunistic network service. + */ + private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers; + + /** * Return subscription Id of the available network. * This value must be one of the entry retrieved from * {@link SubscriptionManager#getOpportunisticSubscriptions} @@ -129,6 +145,22 @@ public final class AvailableNetworkInfo implements Parcelable { return (List<Integer>) mBands.clone(); } + /** + * Returns a list of {@link RadioAccessSpecifier} associated with the available network. + * Opportunistic network service will use this to determine which bands to scan for. + * + * the returned value is one of {@link AccessNetworkConstants.AccessNetworkType}. When no + * specific access network type is specified, {@link RadioAccessSpecifier}s with {@link + * AccessNetworkType}s of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link + * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed + * by Opportunistic network service. + * @return the access network type associated with the available network. + * @hide + */ + public List<RadioAccessSpecifier> getRadioAccessSpecifiers() { + return (List<RadioAccessSpecifier>) mRadioAccessSpecifiers.clone(); + } + @Override public int describeContents() { return 0; @@ -140,6 +172,7 @@ public final class AvailableNetworkInfo implements Parcelable { dest.writeInt(mPriority); dest.writeStringList(mMccMncs); dest.writeList(mBands); + dest.writeList(mRadioAccessSpecifiers); } private AvailableNetworkInfo(Parcel in) { @@ -149,14 +182,25 @@ public final class AvailableNetworkInfo implements Parcelable { in.readStringList(mMccMncs); mBands = new ArrayList<>(); in.readList(mBands, Integer.class.getClassLoader()); + mRadioAccessSpecifiers = new ArrayList<>(); + in.readList(mRadioAccessSpecifiers, RadioAccessSpecifier.class.getClassLoader()); } public AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs, @NonNull List<Integer> bands) { + this(subId, priority, mccMncs, bands, + new ArrayList<RadioAccessSpecifier>()); + } + + /** @hide */ + private AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs, + @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier> + radioAccessSpecifiers) { mSubId = subId; mPriority = priority; mMccMncs = new ArrayList<String>(mccMncs); mBands = new ArrayList<Integer>(bands); + mRadioAccessSpecifiers = new ArrayList<RadioAccessSpecifier>(radioAccessSpecifiers); } @Override @@ -177,12 +221,13 @@ public final class AvailableNetworkInfo implements Parcelable { && mPriority == ani.mPriority && (((mMccMncs != null) && mMccMncs.equals(ani.mMccMncs))) - && mBands.equals(ani.mBands)); + && mBands.equals(ani.mBands)) + && mRadioAccessSpecifiers.equals(ani.getRadioAccessSpecifiers()); } @Override public int hashCode() { - return Objects.hash(mSubId, mPriority, mMccMncs, mBands); + return Objects.hash(mSubId, mPriority, mMccMncs, mBands, mRadioAccessSpecifiers); } public static final @android.annotation.NonNull Parcelable.Creator<AvailableNetworkInfo> CREATOR = @@ -204,6 +249,72 @@ public final class AvailableNetworkInfo implements Parcelable { + " mSubId: " + mSubId + " mPriority: " + mPriority + " mMccMncs: " + Arrays.toString(mMccMncs.toArray()) - + " mBands: " + Arrays.toString(mBands.toArray())); + + " mBands: " + Arrays.toString(mBands.toArray()) + + " mRadioAccessSpecifiers: " + Arrays.toString(mRadioAccessSpecifiers.toArray())); + } + + /** + * Provides a convenient way to set the fields of a {@link AvailableNetworkInfo} when + * creating a new instance. + * + * <p>The example below shows how you might create a new {@code AvailableNetworkInfo}: + * + * <pre><code> + * + * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder() + * .setSubId(1) + * .setPriority(AvailableNetworkInfo.PRIORITY_MED) + * .build(); + * </code></pre> + * + * @hide + */ + public static final class Builder { + private int mSubId = Integer.MIN_VALUE; + private int mPriority = AvailableNetworkInfo.PRIORITY_LOW; + private ArrayList<String> mMccMncs = new ArrayList<>(); + private ArrayList<Integer> mBands = new ArrayList<>(); + private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers = new ArrayList<>(); + + public @NonNull Builder setSubId(int subId) { + mSubId = subId; + return this; + } + + public @NonNull Builder setPriority(int priority) { + if (priority > AvailableNetworkInfo.PRIORITY_LOW + || priority < AvailableNetworkInfo.PRIORITY_HIGH) { + throw new IllegalArgumentException("A valid priority must be set"); + } + mPriority = priority; + return this; + } + + public @NonNull Builder setMccMncs(@NonNull ArrayList<String> mccMncs) { + Objects.requireNonNull(mccMncs, "A non-null ArrayList of mccmncs must be set. An empty " + + "list is still accepted. Please read documentation in " + + "AvailableNetworkService to see consequences of an empty Arraylist."); + mMccMncs = mccMncs; + return this; + } + + public @NonNull Builder setRadioAccessSpecifiers( + @NonNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers) { + Objects.requireNonNull(radioAccessSpecifiers, "A non-null ArrayList of " + + "RadioAccessSpecifiers must be set. An empty list is still accepted. Please " + + "read documentation in AvailableNetworkService to see consequences of an " + + "empty Arraylist."); + mRadioAccessSpecifiers = radioAccessSpecifiers; + return this; + } + + public @NonNull AvailableNetworkInfo build() { + if (mSubId == Integer.MIN_VALUE) { + throw new IllegalArgumentException("A valid subId must be set"); + } + + return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, mBands, + mRadioAccessSpecifiers); + } } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 72ad23b8edb1..68ef7543c33f 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3751,6 +3751,109 @@ public class CarrierConfigManager { "opportunistic_network_max_backoff_time_long"; /** + * Controls SS-RSRP threshold in dBm at which 5G opportunistic network will be considered good + * enough for internet data. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRP_INT = + "opportunistic_network_entry_threshold_ss_rsrp_int"; + + /** + * Controls SS-RSRQ threshold in dB at which 5G opportunistic network will be considered good + * enough for internet data. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE = + "opportunistic_network_entry_threshold_ss_rsrq_double"; + + /** + * Controls SS-RSRP threshold in dBm below which 5G opportunistic network available will not + * be considered good enough for internet data. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT = + "opportunistic_network_exit_threshold_ss_rsrp_int"; + + /** + * Controls SS-RSRQ threshold in dB below which 5G opportunistic network available will not + * be considered good enough for internet data. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_DOUBLE = + "opportunistic_network_exit_threshold_ss_rsrq_double"; + + /** + * Controls back off time in milliseconds for switching back to + * 5G opportunistic subscription. This time will be added to + * {@link CarrierConfigManager#KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG} to + * determine hysteresis time if there is ping pong situation + * (determined by system app or 1st party app) between primary and 5G opportunistic + * subscription. Ping ping situation is defined in + * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG. + * If ping pong situation continuous #KEY_OPPORTUNISTIC_5G_NETWORK_BACKOFF_TIME_LONG + * will be added to previously determined hysteresis time. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG = + "opportunistic_network_5g_backoff_time_long"; + + /** + * Controls the max back off time in milliseconds for switching back to + * 5G opportunistic subscription. + * This time will be the max hysteresis that can be determined irrespective of there is + * continuous ping pong situation or not as described in + * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG and + * #KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_5G_MAX_BACKOFF_TIME_LONG = + "opportunistic_network_5g_max_backoff_time_long"; + + /** + * Controls the ping pong determination of 5G opportunistic network. + * If opportunistic network is determined as out of service or below + * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT or + * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_INT within + * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG of switching to opportunistic network, + * it will be determined as ping pong situation by system app or 1st party app. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG = + "opportunistic_network_5g_ping_pong_time_long"; + + /** + * Controls hysteresis time in milliseconds for which will be waited before switching + * data to a 5G opportunistic network. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG = + "opportunistic_network_5g_data_switch_hysteresis_time_long"; + + /** + * Controls hysteresis time in milliseconds for which will be waited before switching from + * 5G opportunistic network to primary network. + * + * @hide + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG = + "opportunistic_network_5g_data_switch_exit_hysteresis_time_long"; + /** + * Controls whether 4G opportunistic networks should be scanned for possible data switch. + * + * @hide + */ + public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL = + "enabled_4g_opportunistic_network_scan_bool"; + + /** * Indicates zero or more emergency number prefix(es), because some carrier requires * if users dial an emergency number address with a specific prefix, the combination of the * prefix and the address is also a valid emergency number to dial. For example, an emergency @@ -5058,6 +5161,16 @@ public class CarrierConfigManager { "display_no_data_notification_on_permanent_failure_bool"; /** + * Boolean indicating if the VoNR setting is visible in the Call Settings menu. + * If true, the VoNR setting menu will be visible. If false, the menu will be gone. + * + * Disabled by default. + * + * @hide + */ + public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool"; + + /** * Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes * * @hide @@ -5581,7 +5694,25 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG, 10000); /* Default value is 60 seconds. */ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000); - sDefaults.putAll(ImsServiceEntitlement.getDefaults()); + /* Default value is -111 dBm. */ + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRP_INT, -111); + /* Default value is -18.5 dB. */ + sDefaults.putDouble(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE, -18.5); + /* Default value is -120 dBm. */ + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT, -120); + /* Default value is -18.5 dB. */ + sDefaults.putDouble(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_DOUBLE, -18.5); + /* Default value is 10 seconds. */ + sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG, 10000); + /* Default value is 60 seconds. */ + sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_MAX_BACKOFF_TIME_LONG, 60000); + /* Default value is 60 seconds. */ + sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG, 60000); + /* Default value is 2 seconds. */ + sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG, 2000); + /* Default value is 2 seconds. */ + sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000); + sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true); sDefaults.putAll(Gps.getDefaults()); sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY, new int[] { @@ -5653,6 +5784,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, ""); sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false); sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); + sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false); } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 255a61266ebf..abab426b3252 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3483,7 +3483,8 @@ public class TelephonyManager { */ private int getLogicalSlotIndex(int physicalSlotIndex) { UiccSlotInfo[] slotInfos = getUiccSlotsInfo(); - if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length) { + if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length + && slotInfos[physicalSlotIndex] != null) { return slotInfos[physicalSlotIndex].getLogicalSlotIdx(); } @@ -12143,6 +12144,100 @@ public class TelephonyManager { } /** + * No error. Operation succeeded. + * @hide + */ + public static final int ENABLE_VONR_SUCCESS = 0; + + /** + * Radio is not available. + * @hide + */ + public static final int ENABLE_VONR_RADIO_NOT_AVAILABLE = 2; + + /** + * Internal Radio error. + * @hide + */ + public static final int ENABLE_VONR_RADIO_ERROR = 3; + + /** + * Voice over NR enable/disable request is received when system is in invalid state. + * @hide + */ + public static final int ENABLE_VONR_RADIO_INVALID_STATE = 4; + + /** + * Voice over NR enable/disable request is not supported. + * @hide + */ + public static final int ENABLE_VONR_REQUEST_NOT_SUPPORTED = 5; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EnableVoNrResult"}, value = { + ENABLE_VONR_SUCCESS, + ENABLE_VONR_RADIO_NOT_AVAILABLE, + ENABLE_VONR_RADIO_ERROR, + ENABLE_VONR_RADIO_INVALID_STATE, + ENABLE_VONR_REQUEST_NOT_SUPPORTED}) + public @interface EnableVoNrResult {} + + /** + * Enable or disable Voice over NR (VoNR) + * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param enabled enable or disable VoNR. + * @throws IllegalStateException if the Telephony process is not currently available. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public @EnableVoNrResult int setVoNrEnabled(boolean enabled) { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.setVoNrEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#setVoNrEnabled", e); + } + + return ENABLE_VONR_RADIO_INVALID_STATE; + } + + /** + * Is Voice over NR (VoNR) enabled. + * @return true if Voice over NR (VoNR) is enabled else false. Enabled state does not mean + * voice call over NR is active or voice ove NR is available. It means the device is allowed to + * register IMS over NR. + * @throws IllegalStateException if the Telephony process is not currently available. + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isVoNrEnabled() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isVoNrEnabled(getSubId()); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "isVoNrEnabled RemoteException", ex); + ex.rethrowFromSystemServer(); + } + return false; + } + + /** * Carrier action to start or stop reporting default network available events. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 018dabfdb552..89e39256bf09 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2228,6 +2228,20 @@ interface ITelephony { List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId); /** + * Enable or disable Voice over NR (VoNR) + * @param subId the subscription ID that this action applies to. + * @param enabled enable or disable VoNR. + * @return operation result. + */ + int setVoNrEnabled(int subId, boolean enabled); + + /** + * Is voice over NR enabled + * @return true if VoNR is enabled else false + */ + boolean isVoNrEnabled(int subId); + + /** * Enable/Disable E-UTRA-NR Dual Connectivity * @return operation result. See TelephonyManager.EnableNrDualConnectivityResult for * details diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index fe8e6715fe35..fadc23b315d6 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -528,6 +528,8 @@ public interface RILConstants { int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222; int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223; int RIL_REQUEST_GET_SLICING_CONFIG = 224; + int RIL_REQUEST_ENABLE_VONR = 225; + int RIL_REQUEST_IS_VONR_ENABLED = 225; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; |