Merge "Implemented WebView.isVisibleToUserForAutofill()" into pi-dev
diff --git a/Android.bp b/Android.bp
index 1b9210c..1caa497 100644
--- a/Android.bp
+++ b/Android.bp
@@ -813,6 +813,7 @@
],
srcs: [
+ "core/proto/android/os/backtrace.proto",
"core/proto/android/os/batterytype.proto",
"core/proto/android/os/cpufreq.proto",
"core/proto/android/os/cpuinfo.proto",
diff --git a/Android.mk b/Android.mk
index 308a85a..bbe2faf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -333,8 +333,6 @@
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-referenceonly \
-api $(INTERNAL_PLATFORM_API_FILE) \
- -privateApi $(INTERNAL_PLATFORM_PRIVATE_API_FILE) \
- -privateDexApi $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
-nodocs
@@ -345,8 +343,7 @@
include $(BUILD_DROIDDOC)
$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_API_FILE) \
- $(INTERNAL_PLATFORM_PRIVATE_API_FILE) \
- $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+ $(INTERNAL_PLATFORM_REMOVED_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
# ==== the system api stubs ===================================
@@ -371,8 +368,6 @@
-referenceonly \
-showAnnotation android.annotation.SystemApi \
-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
- -privateApi $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_API_FILE) \
- -privateDexApi $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_DEX_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
-exactApi $(INTERNAL_PLATFORM_SYSTEM_EXACT_API_FILE) \
-nodocs
@@ -384,8 +379,8 @@
include $(BUILD_DROIDDOC)
$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
- $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_API_FILE) \
- $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_DEX_API_FILE)
+ $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
+ $(INTERNAL_PLATFORM_SYSTEM_EXACT_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
# ==== the test api stubs ===================================
@@ -421,9 +416,43 @@
include $(BUILD_DROIDDOC)
-$(INTERNAL_PLATFORM_TEST_API_FILE): $(full_target)
+$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_TEST_API_FILE) \
+ $(INTERNAL_PLATFORM_TEST_REMOVED_API_FILE) \
+ $(INTERNAL_PLATFORM_TEST_EXACT_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
+# ==== the complete hidden api list ===================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
+LOCAL_GENERATED_SOURCES:=$(framework_docs_LOCAL_GENERATED_SOURCES)
+LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+
+LOCAL_MODULE := hidden-api-list
+
+LOCAL_DROIDDOC_OPTIONS:=\
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
+ -showUnannotated \
+ -showAnnotation android.annotation.SystemApi \
+ -showAnnotation android.annotation.TestApi \
+ -privateDexApi $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+ -nodocs
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
+
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_DROIDDOC)
+
+$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+
# ==== check javadoc comments but don't generate docs ========
include $(CLEAR_VARS)
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
new file mode 100644
index 0000000..55b97e7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2018 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 android.widget;
+
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Typeface;
+import android.graphics.Canvas;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.PrecomputedText;
+import android.text.Layout;
+import android.text.BoringLayout;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.style.TextAppearanceSpan;
+import android.view.LayoutInflater;
+import android.text.TextPerfUtils;
+import android.view.View.MeasureSpec;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
+
+import com.android.perftests.core.R;
+
+import java.util.Random;
+import java.util.Locale;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+import static android.widget.TextView.UNKNOWN_BORING;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TextViewPrecomputedTextPerfTest {
+ private static final int WORD_LENGTH = 9; // Random word has 9 characters.
+ private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
+ private static final boolean NO_STYLE_TEXT = false;
+ private static final boolean STYLE_TEXT = true;
+
+ private static TextPaint PAINT = new TextPaint();
+ private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
+
+ public TextViewPrecomputedTextPerfTest() {}
+
+ private static class TestableTextView extends TextView {
+ public TestableTextView(Context ctx) {
+ super(ctx);
+ }
+
+ public void onMeasure(int w, int h) {
+ super.onMeasure(w, h);
+ }
+
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ }
+ }
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private TextPerfUtils mTextUtil = new TextPerfUtils();
+
+ @Before
+ public void setUp() {
+ mTextUtil.resetRandom(0 /* seed */);
+ }
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void testNewLayout_RandomText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TextView textView = new TextView(getContext());
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ textView.setText(text);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
+ TEXT_WIDTH, false);
+ }
+ }
+
+ @Test
+ public void testNewLayout_PrecomputedText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TextView textView = new TextView(getContext());
+ textView.setTextMetricsParams(params);
+ textView.setText(text);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
+ TEXT_WIDTH, false);
+ }
+ }
+
+ @Test
+ public void testNewLayout_PrecomputedText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TextView textView = new TextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setTextMetricsParams(params);
+ textView.setText(text);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
+ TEXT_WIDTH, false);
+ }
+ }
+
+ @Test
+ public void testSetText_RandomText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TextView textView = new TextView(getContext());
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.setText(text);
+ }
+ }
+
+ @Test
+ public void testSetText_PrecomputedText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TextView textView = new TextView(getContext());
+ textView.setTextMetricsParams(params);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.setText(text);
+ }
+ }
+
+ @Test
+ public void testSetText_PrecomputedText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TextView textView = new TextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setTextMetricsParams(params);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.setText(text);
+ }
+ }
+
+ @Test
+ public void testOnMeasure_RandomText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
+ int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ textView.setText(text);
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onMeasure(width, height);
+ }
+ }
+
+ @Test
+ public void testOnMeasure_PrecomputedText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
+ int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setTextMetricsParams(params);
+ textView.setText(text);
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onMeasure(width, height);
+ }
+ }
+
+ @Test
+ public void testOnMeasure_PrecomputedText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
+ int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setTextMetricsParams(params);
+ textView.setText(text);
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onMeasure(width, height);
+ }
+ }
+
+ @Test
+ public void testOnDraw_RandomText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
+ int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ textView.setText(text);
+ textView.nullLayouts();
+ textView.onMeasure(width, height);
+ final DisplayListCanvas c = node.start(
+ textView.getMeasuredWidth(), textView.getMeasuredHeight());
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onDraw(c);
+ }
+ }
+
+ @Test
+ public void testOnDraw_PrecomputedText() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
+ int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setTextMetricsParams(params);
+ textView.setText(text);
+ textView.nullLayouts();
+ textView.onMeasure(width, height);
+ final DisplayListCanvas c = node.start(
+ textView.getMeasuredWidth(), textView.getMeasuredHeight());
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onDraw(c);
+ }
+ }
+
+ @Test
+ public void testOnDraw_PrecomputedText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
+ int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
+ final CharSequence text = PrecomputedText.create(
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setTextMetricsParams(params);
+ textView.setText(text);
+ textView.nullLayouts();
+ textView.onMeasure(width, height);
+ final DisplayListCanvas c = node.start(
+ textView.getMeasuredWidth(), textView.getMeasuredHeight());
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onDraw(c);
+ }
+ }
+}
diff --git a/api/current.txt b/api/current.txt
index 2113d5d..a78bd2e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4265,6 +4265,7 @@
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
+ method public static java.lang.String getProcessName();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onCreate();
method public void onLowMemory();
@@ -5752,8 +5753,15 @@
field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0
field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1
field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2
- field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
- field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_AMBIENT = 128; // 0x80
+ field public static final int SUPPRESSED_EFFECT_BADGE = 64; // 0x40
+ field public static final int SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 4; // 0x4
+ field public static final int SUPPRESSED_EFFECT_LIGHTS = 8; // 0x8
+ field public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 256; // 0x100
+ field public static final int SUPPRESSED_EFFECT_PEEK = 16; // 0x10
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_STATUS_BAR = 32; // 0x20
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -7172,13 +7180,13 @@
method public java.util.List<android.app.slice.SliceItem> getItems();
method public android.app.slice.SliceSpec getSpec();
method public android.net.Uri getUri();
+ method public boolean isCallerNeeded();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
field public static final java.lang.String EXTRA_RANGE_VALUE = "android.app.slice.extra.RANGE_VALUE";
field public static final deprecated java.lang.String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
field public static final java.lang.String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
field public static final java.lang.String HINT_ACTIONS = "actions";
- field public static final java.lang.String HINT_CALLER_NEEDED = "caller_needed";
field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
field public static final java.lang.String HINT_KEY_WORDS = "key_words";
field public static final java.lang.String HINT_LARGE = "large";
@@ -7225,6 +7233,7 @@
method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.lang.String...);
method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.util.List<java.lang.String>);
method public android.app.slice.Slice build();
+ method public android.app.slice.Slice.Builder setCallerNeeded(boolean);
method public android.app.slice.Slice.Builder setSpec(android.app.slice.SliceSpec);
}
@@ -7261,19 +7270,11 @@
method public java.util.Collection<android.net.Uri> getSliceDescendants(android.net.Uri);
method public android.net.Uri mapIntentToUri(android.content.Intent);
method public void pinSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
- method public deprecated void registerSliceCallback(android.net.Uri, android.app.slice.SliceManager.SliceCallback, java.util.List<android.app.slice.SliceSpec>);
- method public deprecated void registerSliceCallback(android.net.Uri, android.app.slice.SliceManager.SliceCallback, java.util.List<android.app.slice.SliceSpec>, java.util.concurrent.Executor);
- method public void registerSliceCallback(android.net.Uri, java.util.List<android.app.slice.SliceSpec>, android.app.slice.SliceManager.SliceCallback);
- method public void registerSliceCallback(android.net.Uri, java.util.List<android.app.slice.SliceSpec>, java.util.concurrent.Executor, android.app.slice.SliceManager.SliceCallback);
method public void unpinSlice(android.net.Uri);
- method public void unregisterSliceCallback(android.net.Uri, android.app.slice.SliceManager.SliceCallback);
+ field public static final java.lang.String CATEGORY_SLICE = "android.app.slice.category.SLICE";
field public static final java.lang.String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
}
- public static abstract interface SliceManager.SliceCallback {
- method public abstract void onSliceUpdated(android.app.slice.Slice);
- }
-
public abstract class SliceProvider extends android.content.ContentProvider {
ctor public SliceProvider();
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
@@ -13609,11 +13610,19 @@
method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source) throws java.io.IOException;
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source) throws java.io.IOException;
+ method public int getAllocator();
+ method public boolean getConserveMemory();
+ method public android.graphics.Rect getCrop();
+ method public boolean getDecodeAsAlphaMask();
+ method public boolean getMutable();
+ method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
+ method public android.graphics.PostProcessor getPostProcessor();
+ method public boolean getRequireUnpremultiplied();
method public android.util.Size getSampledSize(int);
method public android.graphics.ImageDecoder setAllocator(int);
- method public android.graphics.ImageDecoder setAsAlphaMask(boolean);
method public android.graphics.ImageDecoder setConserveMemory(boolean);
method public android.graphics.ImageDecoder setCrop(android.graphics.Rect);
+ method public android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
method public android.graphics.ImageDecoder setMutable(boolean);
method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
@@ -16426,8 +16435,8 @@
}
public final class SessionConfiguration {
- ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler);
- method public android.os.Handler getHandler();
+ ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
+ method public java.util.concurrent.Executor getExecutor();
method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
method public android.hardware.camera2.CaptureRequest getSessionParameters();
@@ -21217,7 +21226,7 @@
method public void onWindowHidden();
method public void onWindowShown();
method public void requestHideSelf(int);
- method public void requestShowSelf(int);
+ method public final void requestShowSelf(int);
method public boolean sendDefaultEditorAction(boolean);
method public void sendDownUpKeyEvents(int);
method public void sendKeyChar(char);
@@ -21227,13 +21236,13 @@
method public void setExtractView(android.view.View);
method public void setExtractViewShown(boolean);
method public void setInputView(android.view.View);
- method public boolean shouldOfferSwitchingToNextInputMethod();
+ method public final boolean shouldOfferSwitchingToNextInputMethod();
method public void showStatusIcon(int);
method public void showWindow(boolean);
method public void switchInputMethod(java.lang.String);
- method public void switchInputMethod(java.lang.String, android.view.inputmethod.InputMethodSubtype);
- method public boolean switchToNextInputMethod(boolean);
- method public boolean switchToPreviousInputMethod();
+ method public final void switchInputMethod(java.lang.String, android.view.inputmethod.InputMethodSubtype);
+ method public final boolean switchToNextInputMethod(boolean);
+ method public final boolean switchToPreviousInputMethod();
method public void updateFullscreenMode();
method public void updateInputViewShown();
field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
@@ -23249,6 +23258,7 @@
field public static final int HEVCProfileMain = 1; // 0x1
field public static final int HEVCProfileMain10 = 2; // 0x2
field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
+ field public static final int HEVCProfileMainStill = 4; // 0x4
field public static final int MPEG2LevelH14 = 2; // 0x2
field public static final int MPEG2LevelHL = 3; // 0x3
field public static final int MPEG2LevelHP = 4; // 0x4
@@ -27581,17 +27591,17 @@
field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
- field public static final int TYPE_BLUETOOTH = 7; // 0x7
- field public static final int TYPE_DUMMY = 8; // 0x8
- field public static final int TYPE_ETHERNET = 9; // 0x9
- field public static final int TYPE_MOBILE = 0; // 0x0
- field public static final int TYPE_MOBILE_DUN = 4; // 0x4
+ field public static final deprecated int TYPE_BLUETOOTH = 7; // 0x7
+ field public static final deprecated int TYPE_DUMMY = 8; // 0x8
+ field public static final deprecated int TYPE_ETHERNET = 9; // 0x9
+ field public static final deprecated int TYPE_MOBILE = 0; // 0x0
+ field public static final deprecated int TYPE_MOBILE_DUN = 4; // 0x4
field public static final deprecated int TYPE_MOBILE_HIPRI = 5; // 0x5
field public static final deprecated int TYPE_MOBILE_MMS = 2; // 0x2
field public static final deprecated int TYPE_MOBILE_SUPL = 3; // 0x3
- field public static final int TYPE_VPN = 17; // 0x11
- field public static final int TYPE_WIFI = 1; // 0x1
- field public static final int TYPE_WIMAX = 6; // 0x6
+ field public static final deprecated int TYPE_VPN = 17; // 0x11
+ field public static final deprecated int TYPE_WIFI = 1; // 0x1
+ field public static final deprecated int TYPE_WIMAX = 6; // 0x6
}
public static class ConnectivityManager.NetworkCallback {
@@ -27868,16 +27878,16 @@
method public int describeContents();
method public android.net.NetworkInfo.DetailedState getDetailedState();
method public java.lang.String getExtraInfo();
- method public java.lang.String getReason();
- method public android.net.NetworkInfo.State getState();
+ method public deprecated java.lang.String getReason();
+ method public deprecated android.net.NetworkInfo.State getState();
method public int getSubtype();
method public java.lang.String getSubtypeName();
- method public int getType();
- method public java.lang.String getTypeName();
- method public boolean isAvailable();
+ method public deprecated int getType();
+ method public deprecated java.lang.String getTypeName();
+ method public deprecated boolean isAvailable();
method public boolean isConnected();
- method public boolean isConnectedOrConnecting();
- method public boolean isFailover();
+ method public deprecated boolean isConnectedOrConnecting();
+ method public deprecated boolean isFailover();
method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
@@ -37144,6 +37154,7 @@
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
+ field public static final java.lang.String ACTION_DATA_USAGE_SETTINGS = "android.settings.DATA_USAGE_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
@@ -40000,8 +40011,8 @@
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
field public static final int REASON_USER_STOPPED = 6; // 0x6
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
- field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
- field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+ field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
}
public static class NotificationListenerService.Ranking {
@@ -41379,10 +41390,10 @@
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
- field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
- field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
- field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
- field public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 5; // 0x5
+ field public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2; // 0x2
+ field public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 4; // 0x4
+ field public static final int HANDOVER_FAILURE_UNKNOWN = 5; // 0x5
+ field public static final int HANDOVER_FAILURE_USER_REJECTED = 3; // 0x3
}
public static class Call.Details {
@@ -42139,11 +42150,9 @@
package android.telephony {
public final class AccessNetworkConstants {
- ctor public AccessNetworkConstants();
}
public static final class AccessNetworkConstants.AccessNetworkType {
- ctor public AccessNetworkConstants.AccessNetworkType();
field public static final int CDMA2000 = 4; // 0x4
field public static final int EUTRAN = 3; // 0x3
field public static final int GERAN = 1; // 0x1
@@ -42153,7 +42162,6 @@
}
public static final class AccessNetworkConstants.EutranBand {
- ctor public AccessNetworkConstants.EutranBand();
field public static final int BAND_1 = 1; // 0x1
field public static final int BAND_10 = 10; // 0xa
field public static final int BAND_11 = 11; // 0xb
@@ -42205,7 +42213,6 @@
}
public static final class AccessNetworkConstants.GeranBand {
- ctor public AccessNetworkConstants.GeranBand();
field public static final int BAND_450 = 3; // 0x3
field public static final int BAND_480 = 4; // 0x4
field public static final int BAND_710 = 5; // 0x5
@@ -42223,7 +42230,6 @@
}
public static final class AccessNetworkConstants.UtranBand {
- ctor public AccessNetworkConstants.UtranBand();
field public static final int BAND_1 = 1; // 0x1
field public static final int BAND_10 = 10; // 0xa
field public static final int BAND_11 = 11; // 0xb
@@ -42664,7 +42670,8 @@
}
public class NetworkScan {
- method public void stop() throws android.os.RemoteException;
+ method public deprecated void stop() throws android.os.RemoteException;
+ method public void stopScan();
field public static final int ERROR_INTERRUPTED = 10002; // 0x2712
field public static final int ERROR_INVALID_SCAN = 2; // 0x2
field public static final int ERROR_INVALID_SCANID = 10001; // 0x2711
@@ -43129,7 +43136,8 @@
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
- method public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
+ method public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
+ method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
@@ -51030,6 +51038,74 @@
package android.view.textclassifier {
+ public abstract class Logger {
+ ctor public Logger(android.view.textclassifier.Logger.Config);
+ method public java.text.BreakIterator getTokenIterator(java.util.Locale);
+ method public boolean isSmartSelection(java.lang.String);
+ method public final void logSelectionActionEvent(int, int, int);
+ method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
+ method public final void logSelectionModifiedEvent(int, int);
+ method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
+ method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
+ method public final void logSelectionStartedEvent(int, int);
+ method public abstract void writeEvent(android.view.textclassifier.SelectionEvent);
+ field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
+ field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
+ field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
+ field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
+ field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
+ field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
+ field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
+ field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
+ field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
+ field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
+ field public static final java.lang.String WIDGET_WEBVIEW = "webview";
+ }
+
+ public static final class Logger.Config {
+ ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
+ method public java.lang.String getPackageName();
+ method public java.lang.String getWidgetType();
+ method public java.lang.String getWidgetVersion();
+ }
+
+ public final class SelectionEvent {
+ method public long getDurationSincePreviousEvent();
+ method public long getDurationSinceSessionStart();
+ method public int getEnd();
+ method public java.lang.String getEntityType();
+ method public int getEventIndex();
+ method public long getEventTime();
+ method public int getEventType();
+ method public int getInvocationMethod();
+ method public java.lang.String getPackageName();
+ method public java.lang.String getSessionId();
+ method public java.lang.String getSignature();
+ method public int getSmartEnd();
+ method public int getSmartStart();
+ method public int getStart();
+ method public java.lang.String getWidgetType();
+ method public java.lang.String getWidgetVersion();
+ field public static final int ACTION_ABANDON = 107; // 0x6b
+ field public static final int ACTION_COPY = 101; // 0x65
+ field public static final int ACTION_CUT = 103; // 0x67
+ field public static final int ACTION_DRAG = 106; // 0x6a
+ field public static final int ACTION_OTHER = 108; // 0x6c
+ field public static final int ACTION_OVERTYPE = 100; // 0x64
+ field public static final int ACTION_PASTE = 102; // 0x66
+ field public static final int ACTION_RESET = 201; // 0xc9
+ field public static final int ACTION_SELECT_ALL = 200; // 0xc8
+ field public static final int ACTION_SHARE = 104; // 0x68
+ field public static final int ACTION_SMART_SHARE = 105; // 0x69
+ field public static final int EVENT_AUTO_SELECTION = 5; // 0x5
+ field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2
+ field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
+ field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
+ field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
+ field public static final int INVOCATION_LINK = 2; // 0x2
+ field public static final int INVOCATION_MANUAL = 1; // 0x1
+ }
+
public final class TextClassification implements android.os.Parcelable {
method public int describeContents();
method public float getConfidenceScore(java.lang.String);
@@ -51086,7 +51162,7 @@
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
- method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config);
+ method public default android.view.textclassifier.Logger getLogger(android.view.textclassifier.Logger.Config);
method public default int getMaxGenerateLinksTextLength();
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
@@ -51199,78 +51275,6 @@
}
-package android.view.textclassifier.logging {
-
- public abstract class Logger {
- ctor public Logger(android.view.textclassifier.logging.Logger.Config);
- method public java.text.BreakIterator getTokenIterator(java.util.Locale);
- method public boolean isSmartSelection(java.lang.String);
- method public final void logSelectionActionEvent(int, int, int);
- method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
- method public final void logSelectionModifiedEvent(int, int);
- method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
- method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
- method public final void logSelectionStartedEvent(int, int);
- method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent);
- field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
- field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
- field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
- field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
- field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
- field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
- field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
- field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
- field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
- field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
- field public static final java.lang.String WIDGET_WEBVIEW = "webview";
- }
-
- public static final class Logger.Config {
- ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
- method public java.lang.String getPackageName();
- method public java.lang.String getWidgetType();
- method public java.lang.String getWidgetVersion();
- }
-
- public final class SelectionEvent {
- method public long getDurationSincePreviousEvent();
- method public long getDurationSinceSessionStart();
- method public int getEnd();
- method public java.lang.String getEntityType();
- method public int getEventIndex();
- method public long getEventTime();
- method public int getEventType();
- method public int getInvocationMethod();
- method public java.lang.String getPackageName();
- method public java.lang.String getSessionId();
- method public java.lang.String getSignature();
- method public int getSmartEnd();
- method public int getSmartStart();
- method public int getStart();
- method public java.lang.String getWidgetType();
- method public java.lang.String getWidgetVersion();
- field public static final int ACTION_ABANDON = 107; // 0x6b
- field public static final int ACTION_COPY = 101; // 0x65
- field public static final int ACTION_CUT = 103; // 0x67
- field public static final int ACTION_DRAG = 106; // 0x6a
- field public static final int ACTION_OTHER = 108; // 0x6c
- field public static final int ACTION_OVERTYPE = 100; // 0x64
- field public static final int ACTION_PASTE = 102; // 0x66
- field public static final int ACTION_RESET = 201; // 0xc9
- field public static final int ACTION_SELECT_ALL = 200; // 0xc8
- field public static final int ACTION_SHARE = 104; // 0x68
- field public static final int ACTION_SMART_SHARE = 105; // 0x69
- field public static final int EVENT_AUTO_SELECTION = 5; // 0x5
- field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2
- field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
- field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
- field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
- field public static final int INVOCATION_LINK = 2; // 0x2
- field public static final int INVOCATION_MANUAL = 1; // 0x1
- }
-
-}
-
package android.view.textservice {
public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -53390,6 +53394,9 @@
public final class Magnifier {
ctor public Magnifier(android.view.View);
method public void dismiss();
+ method public int getHeight();
+ method public int getWidth();
+ method public float getZoom();
method public void show(float, float);
method public void update();
}
diff --git a/api/removed.txt b/api/removed.txt
index b8e2b98..a5370f4 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -152,6 +152,11 @@
method public deprecated boolean clipRegion(android.graphics.Region);
}
+ public final class ImageDecoder implements java.lang.AutoCloseable {
+ method public deprecated boolean getAsAlphaMask();
+ method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+ }
+
public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
ctor public LayerRasterizer();
method public void addLayer(android.graphics.Paint, float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7420720..fffbcd8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1,6 +1,7 @@
package android {
public static final class Manifest.permission {
+ field public static final java.lang.String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
field public static final java.lang.String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
field public static final java.lang.String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
@@ -376,6 +377,7 @@
method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
method public boolean setDataFetchOperation(long, android.app.PendingIntent);
field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
+ field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
@@ -839,6 +841,7 @@
}
public class Intent implements java.lang.Cloneable android.os.Parcelable {
+ field public static final java.lang.String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED";
field public static final java.lang.String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
field public static final java.lang.String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
field public static final java.lang.String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
@@ -1220,6 +1223,7 @@
}
public final class DisplayManager {
+ method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
method public android.graphics.Point getStableDisplaySize();
method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
@@ -2115,8 +2119,15 @@
field public static final java.lang.String METADATA_KEY_ART = "android.hardware.radio.metadata.ART";
field public static final java.lang.String METADATA_KEY_ARTIST = "android.hardware.radio.metadata.ARTIST";
field public static final java.lang.String METADATA_KEY_CLOCK = "android.hardware.radio.metadata.CLOCK";
+ field public static final java.lang.String METADATA_KEY_DAB_COMPONENT_NAME = "android.hardware.radio.metadata.DAB_COMPONENT_NAME";
+ field public static final java.lang.String METADATA_KEY_DAB_COMPONENT_NAME_SHORT = "android.hardware.radio.metadata.DAB_COMPONENT_NAME_SHORT";
+ field public static final java.lang.String METADATA_KEY_DAB_ENSEMBLE_NAME = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME";
+ field public static final java.lang.String METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME_SHORT";
+ field public static final java.lang.String METADATA_KEY_DAB_SERVICE_NAME = "android.hardware.radio.metadata.DAB_SERVICE_NAME";
+ field public static final java.lang.String METADATA_KEY_DAB_SERVICE_NAME_SHORT = "android.hardware.radio.metadata.DAB_SERVICE_NAME_SHORT";
field public static final java.lang.String METADATA_KEY_GENRE = "android.hardware.radio.metadata.GENRE";
field public static final java.lang.String METADATA_KEY_ICON = "android.hardware.radio.metadata.ICON";
+ field public static final java.lang.String METADATA_KEY_PROGRAM_NAME = "android.hardware.radio.metadata.PROGRAM_NAME";
field public static final java.lang.String METADATA_KEY_RBDS_PTY = "android.hardware.radio.metadata.RBDS_PTY";
field public static final java.lang.String METADATA_KEY_RDS_PI = "android.hardware.radio.metadata.RDS_PI";
field public static final java.lang.String METADATA_KEY_RDS_PS = "android.hardware.radio.metadata.RDS_PS";
@@ -3603,6 +3614,11 @@
package android.os {
+ public class BatteryManager {
+ field public static final java.lang.String EXTRA_EVENTS = "android.os.extra.EVENTS";
+ field public static final java.lang.String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
+ }
+
public final class ConfigUpdate {
field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
@@ -4688,6 +4704,7 @@
public abstract class TextClassifierService extends android.app.Service {
ctor public TextClassifierService();
+ method public final android.view.textclassifier.TextClassifier getLocalTextClassifier();
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract void onClassifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
method public abstract void onGenerateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
@@ -4986,7 +5003,6 @@
package android.telephony {
public static final class AccessNetworkConstants.TransportType {
- ctor public AccessNetworkConstants.TransportType();
field public static final int WLAN = 2; // 0x2
field public static final int WWAN = 1; // 0x1
}
@@ -5486,6 +5502,9 @@
}
public final class ImsCallProfile implements android.os.Parcelable {
+ ctor public ImsCallProfile();
+ ctor public ImsCallProfile(int, int);
+ ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
method public java.lang.String getCallExtra(java.lang.String);
method public java.lang.String getCallExtra(java.lang.String, java.lang.String);
@@ -5509,6 +5528,7 @@
method public void setCallExtraInt(java.lang.String, int);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
+ method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; // 0x2
field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
@@ -5846,6 +5866,7 @@
}
public final class ImsStreamMediaProfile implements android.os.Parcelable {
+ ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
method public int getAudioDirection();
@@ -6656,6 +6677,7 @@
method public default boolean isVisibleToUserForAutofill(int);
method public abstract void onActivityResult(int, int, android.content.Intent);
method public abstract void onAttachedToWindow();
+ method public default boolean onCheckIsTextEditor();
method public abstract void onConfigurationChanged(android.content.res.Configuration);
method public abstract android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
method public abstract void onDetachedFromWindow();
diff --git a/api/test-current.txt b/api/test-current.txt
index 2559d24..9d67f4c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -360,6 +360,7 @@
}
public final class DisplayManager {
+ method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
method public android.graphics.Point getStableDisplaySize();
method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 3a47fe1..db864ae 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -15,8 +15,10 @@
LOCAL_PATH:= $(call my-dir)
# proto files used in incidentd to generate cppstream proto headers.
-PROTO_FILES:= frameworks/base/core/proto/android/util/log.proto \
- frameworks/base/core/proto/android/os/data.proto
+PROTO_FILES:= \
+ frameworks/base/core/proto/android/os/backtrace.proto \
+ frameworks/base/core/proto/android/os/data.proto \
+ frameworks/base/core/proto/android/util/log.proto
# ========= #
# incidentd #
@@ -39,18 +41,16 @@
LOCAL_CFLAGS += \
-Os
endif
-
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
LOCAL_SHARED_LIBRARIES := \
libbase \
libbinder \
- libcutils \
+ libdebuggerd_client \
+ libdumputils \
libincident \
liblog \
- libprotobuf-cpp-lite \
libprotoutil \
- libselinux \
libservices \
libutils
@@ -118,12 +118,12 @@
LOCAL_SHARED_LIBRARIES := \
libbase \
libbinder \
- libcutils \
+ libdebuggerd_client \
+ libdumputils \
libincident \
liblog \
libprotobuf-cpp-lite \
libprotoutil \
- libselinux \
libservices \
libutils \
diff --git a/cmds/incidentd/incidentd.rc b/cmds/incidentd/incidentd.rc
index 6dd8114..9c16a1c 100644
--- a/cmds/incidentd/incidentd.rc
+++ b/cmds/incidentd/incidentd.rc
@@ -16,6 +16,7 @@
class main
user incidentd
group incidentd log readproc
+ capabilities KILL SYS_PTRACE
on post-fs-data
# Create directory for incidentd
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 64da677..3570144 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -87,6 +87,35 @@
return NO_ERROR;
}
+status_t FdBuffer::readFully(int fd) {
+ mStartTime = uptimeMillis();
+
+ while (true) {
+ if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+ // Don't let it get too big.
+ mTruncated = true;
+ VLOG("Truncating data");
+ break;
+ }
+ if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
+
+ ssize_t amt =
+ TEMP_FAILURE_RETRY(::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite()));
+ if (amt < 0) {
+ VLOG("Fail to read %d: %s", fd, strerror(errno));
+ return -errno;
+ } else if (amt == 0) {
+ VLOG("Done reading %zu bytes", mBuffer.size());
+ // We're done.
+ break;
+ }
+ mBuffer.wp()->move(amt);
+ }
+
+ mFinishTime = uptimeMillis();
+ return NO_ERROR;
+}
+
status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
const bool isSysfs) {
struct pollfd pfds[] = {
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 66a3de1..34ebcf5 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -41,6 +41,12 @@
status_t read(int fd, int64_t timeoutMs);
/**
+ * Read the data until we hit eof.
+ * Returns NO_ERROR if there were no errors.
+ */
+ status_t readFully(int fd);
+
+ /**
* Read processed results by streaming data to a parsing process, e.g. incident helper.
* The parsing process provides IO fds which are 'toFd' and 'fromFd'. The function
* reads original data in 'fd' and writes to parsing process through 'toFd', then it reads
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 28fb38a..d02b4dd 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -358,8 +358,7 @@
return error;
}
fprintf(err, "Read %zu bytes\n", buf.size());
- auto data = buf.data();
- PrivacyBuffer pBuf(p, data);
+ PrivacyBuffer pBuf(p, buf.data());
PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1);
error = pBuf.strip(spec);
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 73ee1cb..f1f7c589 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -101,7 +101,7 @@
}
// ================================================================================
-PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
+PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator data)
: mPolicy(policy), mData(data), mProto(), mSize(0) {}
PrivacyBuffer::~PrivacyBuffer() {}
diff --git a/cmds/incidentd/src/PrivacyBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
index 92e1a25..cd29d8b 100644
--- a/cmds/incidentd/src/PrivacyBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -34,7 +34,7 @@
*/
class PrivacyBuffer {
public:
- PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
+ PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator data);
~PrivacyBuffer();
/**
@@ -60,7 +60,7 @@
private:
const Privacy* mPolicy;
- EncodedBuffer::iterator& mData;
+ EncodedBuffer::iterator mData;
ProtoOutputStream mProto;
size_t mSize;
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 12764f8..fc8a6db 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -89,11 +89,11 @@
IncidentMetadata::SectionStats* ReportRequestSet::sectionStats(int id) {
if (mSectionStats.find(id) == mSectionStats.end()) {
- auto stats = mMetadata.add_sections();
- stats->set_id(id);
+ IncidentMetadata::SectionStats stats;
+ stats.set_id(id);
mSectionStats[id] = stats;
}
- return mSectionStats[id];
+ return &mSectionStats[id];
}
// ================================================================================
@@ -182,7 +182,7 @@
}
// Execute - go get the data and write it into the file descriptors.
- auto stats = batch.sectionStats(id);
+ IncidentMetadata::SectionStats* stats = batch.sectionStats(id);
int64_t startTime = uptimeMillis();
err = (*section)->Execute(&batch);
int64_t endTime = uptimeMillis();
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index ba8965e..f9a092a 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -66,6 +66,7 @@
int mainFd() { return mMainFd; }
int mainDest() { return mMainDest; }
IncidentMetadata& metadata() { return mMetadata; }
+ map<int, IncidentMetadata::SectionStats>& allSectionStats() { return mSectionStats; }
bool containsSection(int id);
IncidentMetadata::SectionStats* sectionStats(int id);
@@ -77,7 +78,7 @@
int mMainDest;
IncidentMetadata mMetadata;
- map<int, IncidentMetadata::SectionStats*> mSectionStats;
+ map<int, IncidentMetadata::SectionStats> mSectionStats;
};
// ================================================================================
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 46243c05..5cde5a9 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -18,13 +18,19 @@
#include "Section.h"
+#include <dirent.h>
+#include <errno.h>
#include <wait.h>
#include <mutex>
+#include <set>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android/util/protobuf.h>
#include <binder/IServiceManager.h>
+#include <debuggerd/client.h>
+#include <dumputils/dump_utils.h>
#include <log/log_event_list.h>
#include <log/log_read.h>
#include <log/logprint.h>
@@ -33,6 +39,7 @@
#include "FdBuffer.h"
#include "Privacy.h"
#include "PrivacyBuffer.h"
+#include "frameworks/base/core/proto/android/os/backtrace.proto.h"
#include "frameworks/base/core/proto/android/os/data.proto.h"
#include "frameworks/base/core/proto/android/util/log.proto.h"
#include "incidentd_util.h"
@@ -95,13 +102,14 @@
return WriteFully(fd, buf, p - buf) ? NO_ERROR : -errno;
}
+// Reads data from FdBuffer and writes it to the requests file descriptor.
static status_t write_report_requests(const int id, const FdBuffer& buffer,
ReportRequestSet* requests) {
status_t err = -EBADF;
EncodedBuffer::iterator data = buffer.data();
PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
- auto stats = requests->sectionStats(id);
+ IncidentMetadata::SectionStats* stats = requests->sectionStats(id);
stats->set_dump_size_bytes(data.size());
stats->set_dump_duration_ms(buffer.durationMs());
@@ -207,23 +215,48 @@
MetadataSection::~MetadataSection() {}
status_t MetadataSection::Execute(ReportRequestSet* requests) const {
- std::string metadataBuf;
- requests->metadata().SerializeToString(&metadataBuf);
+ ProtoOutputStream proto;
+ IncidentMetadata metadata = requests->metadata();
+ proto.write(FIELD_TYPE_ENUM | IncidentMetadata::kDestFieldNumber, metadata.dest());
+ proto.write(FIELD_TYPE_INT32 | IncidentMetadata::kRequestSizeFieldNumber,
+ metadata.request_size());
+ proto.write(FIELD_TYPE_BOOL | IncidentMetadata::kUseDropboxFieldNumber, metadata.use_dropbox());
+ for (auto iter = requests->allSectionStats().begin(); iter != requests->allSectionStats().end();
+ iter++) {
+ IncidentMetadata::SectionStats stats = iter->second;
+ uint64_t token = proto.start(FIELD_TYPE_MESSAGE | IncidentMetadata::kSectionsFieldNumber);
+ proto.write(FIELD_TYPE_INT32 | IncidentMetadata::SectionStats::kIdFieldNumber, stats.id());
+ proto.write(FIELD_TYPE_BOOL | IncidentMetadata::SectionStats::kSuccessFieldNumber,
+ stats.success());
+ proto.write(FIELD_TYPE_INT32 | IncidentMetadata::SectionStats::kReportSizeBytesFieldNumber,
+ stats.report_size_bytes());
+ proto.write(FIELD_TYPE_INT64 | IncidentMetadata::SectionStats::kExecDurationMsFieldNumber,
+ stats.exec_duration_ms());
+ proto.write(FIELD_TYPE_INT32 | IncidentMetadata::SectionStats::kDumpSizeBytesFieldNumber,
+ stats.dump_size_bytes());
+ proto.write(FIELD_TYPE_INT64 | IncidentMetadata::SectionStats::kDumpDurationMsFieldNumber,
+ stats.dump_duration_ms());
+ proto.write(FIELD_TYPE_BOOL | IncidentMetadata::SectionStats::kTimedOutFieldNumber,
+ stats.timed_out());
+ proto.write(FIELD_TYPE_BOOL | IncidentMetadata::SectionStats::kIsTruncatedFieldNumber,
+ stats.is_truncated());
+ proto.end(token);
+ }
+
for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
const sp<ReportRequest> request = *it;
- if (metadataBuf.empty() || request->fd < 0 || request->err != NO_ERROR) {
+ if (request->fd < 0 || request->err != NO_ERROR) {
continue;
}
- write_section_header(request->fd, id, metadataBuf.size());
- if (!WriteFully(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+ write_section_header(request->fd, id, proto.size());
+ if (!proto.flush(request->fd)) {
ALOGW("Failed to write metadata to fd %d", request->fd);
// we don't fail if we can't write to a single request's fd.
}
}
- if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
- write_section_header(requests->mainFd(), id, metadataBuf.size());
- if (!WriteFully(requests->mainFd(), (uint8_t const*)metadataBuf.data(),
- metadataBuf.size())) {
+ if (requests->mainFd() >= 0) {
+ write_section_header(requests->mainFd(), id, proto.size());
+ if (!proto.flush(requests->mainFd())) {
ALOGW("Failed to write metadata to dropbox fd %d", requests->mainFd());
return -1;
}
@@ -387,6 +420,7 @@
return NO_ERROR;
}
+
// ================================================================================
struct WorkerThreadData : public virtual RefBase {
const WorkerThreadSection* section;
@@ -413,7 +447,8 @@
WorkerThreadData::~WorkerThreadData() {}
// ================================================================================
-WorkerThreadSection::WorkerThreadSection(int id) : Section(id) {}
+WorkerThreadSection::WorkerThreadSection(int id, const int64_t timeoutMs)
+ : Section(id, timeoutMs) {}
WorkerThreadSection::~WorkerThreadSection() {}
@@ -594,7 +629,7 @@
return readStatus;
}
- // TODO: wait for command here has one trade-off: the failed status of command won't be detected
+ // Waiting for command here has one trade-off: the failed status of command won't be detected
// until buffer timeout, but it has advatage on starting the data stream earlier.
status_t cmdStatus = wait_child(cmdPid);
status_t ihStatus = wait_child(ihPid);
@@ -694,7 +729,6 @@
}
status_t LogSection::BlockingCall(int pipeWriteFd) const {
- status_t err = NO_ERROR;
// Open log buffer and getting logs since last retrieved time if any.
unique_ptr<logger_list, void (*)(logger_list*)> loggers(
gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
@@ -705,15 +739,16 @@
if (android_logger_open(loggers.get(), mLogID) == NULL) {
ALOGW("LogSection %s: Can't get logger.", this->name.string());
- return err;
+ return NO_ERROR;
}
log_msg msg;
log_time lastTimestamp(0);
+ status_t err = NO_ERROR;
ProtoOutputStream proto;
while (true) { // keeps reading until logd buffer is fully read.
- status_t err = android_logger_list_read(loggers.get(), &msg);
+ err = android_logger_list_read(loggers.get(), &msg);
// err = 0 - no content, unexpected connection drop or EOF.
// err = +ive number - size of retrieved data from logger
// err = -ive number, OS supplied error _except_ for -EAGAIN
@@ -814,3 +849,133 @@
proto.flush(pipeWriteFd);
return err;
}
+
+// ================================================================================
+
+TombstoneSection::TombstoneSection(int id, const char* type, const int64_t timeoutMs)
+ : WorkerThreadSection(id, timeoutMs), mType(type) {
+ name += "tombstone ";
+ name += type;
+}
+
+TombstoneSection::~TombstoneSection() {}
+
+status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
+ std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+ if (proc.get() == nullptr) {
+ ALOGE("opendir /proc failed: %s\n", strerror(errno));
+ return -errno;
+ }
+
+ const std::set<int> hal_pids = get_interesting_hal_pids();
+
+ ProtoOutputStream proto;
+ struct dirent* d;
+ status_t err = NO_ERROR;
+ while ((d = readdir(proc.get()))) {
+ int pid = atoi(d->d_name);
+ if (pid <= 0) {
+ continue;
+ }
+
+ const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
+ std::string exe;
+ if (!android::base::Readlink(link_name, &exe)) {
+ ALOGE("Can't read '%s': %s\n", link_name.c_str(), strerror(errno));
+ continue;
+ }
+
+ bool is_java_process;
+ if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+ if (mType != "java") continue;
+ // Don't bother dumping backtraces for the zygote.
+ if (IsZygote(pid)) {
+ VLOG("Skipping Zygote");
+ continue;
+ }
+
+ is_java_process = true;
+ } else if (should_dump_native_traces(exe.c_str())) {
+ if (mType != "native") continue;
+ is_java_process = false;
+ } else if (hal_pids.find(pid) != hal_pids.end()) {
+ if (mType != "hal") continue;
+ is_java_process = false;
+ } else {
+ // Probably a native process we don't care about, continue.
+ VLOG("Skipping %d", pid);
+ continue;
+ }
+
+ Fpipe dumpPipe;
+ if (!dumpPipe.init()) {
+ ALOGW("TombstoneSection '%s' failed to setup dump pipe", this->name.string());
+ err = -errno;
+ break;
+ }
+
+ const uint64_t start = Nanotime();
+ pid_t child = fork();
+ if (child < 0) {
+ ALOGE("Failed to fork child process");
+ break;
+ } else if (child == 0) {
+ // This is the child process.
+ close(dumpPipe.readFd());
+ const int ret = dump_backtrace_to_file_timeout(
+ pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
+ is_java_process ? 5 : 20, dumpPipe.writeFd());
+ if (ret == -1) {
+ if (errno == 0) {
+ ALOGW("Dumping failed for pid '%d', likely due to a timeout\n", pid);
+ } else {
+ ALOGE("Dumping failed for pid '%d': %s\n", pid, strerror(errno));
+ }
+ }
+ if (close(dumpPipe.writeFd()) != 0) {
+ ALOGW("TombstoneSection '%s' failed to close dump pipe writeFd: %d",
+ this->name.string(), errno);
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+ close(dumpPipe.writeFd());
+ // Parent process.
+ // Read from the pipe concurrently to avoid blocking the child.
+ FdBuffer buffer;
+ err = buffer.readFully(dumpPipe.readFd());
+ if (err != NO_ERROR) {
+ ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err);
+ if (close(dumpPipe.readFd()) != 0) {
+ ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %s",
+ this->name.string(), strerror(errno));
+ }
+ break;
+ }
+
+ auto dump = std::make_unique<char[]>(buffer.size());
+ auto iterator = buffer.data();
+ int i = 0;
+ while (iterator.hasNext()) {
+ dump[i] = iterator.next();
+ i++;
+ }
+ long long token = proto.start(android::os::BackTraceProto::TRACES);
+ proto.write(android::os::BackTraceProto::Stack::PID, pid);
+ proto.write(android::os::BackTraceProto::Stack::DUMP, dump.get(), i);
+ proto.write(android::os::BackTraceProto::Stack::DUMP_DURATION_NS,
+ static_cast<long long>(Nanotime() - start));
+ proto.end(token);
+
+ if (close(dumpPipe.readFd()) != 0) {
+ ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %d", this->name.string(),
+ errno);
+ err = -errno;
+ break;
+ }
+ }
+
+ proto.flush(pipeWriteFd);
+ return err;
+}
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 8294be1..19ef7ee 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -103,7 +103,7 @@
*/
class WorkerThreadSection : public Section {
public:
- WorkerThreadSection(int id);
+ WorkerThreadSection(int id, const int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
virtual ~WorkerThreadSection();
virtual status_t Execute(ReportRequestSet* requests) const;
@@ -161,4 +161,18 @@
bool mBinary;
};
+/**
+ * Section that gets data from tombstoned.
+ */
+class TombstoneSection : public WorkerThreadSection {
+public:
+ TombstoneSection(int id, const char* type, const int64_t timeoutMs = 30000 /* 30 seconds */);
+ virtual ~TombstoneSection();
+
+ virtual status_t BlockingCall(int pipeWriteFd) const;
+
+private:
+ std::string mType;
+};
+
#endif // SECTIONS_H
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index c095f2b..c869c7a 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -80,6 +80,7 @@
close(output->writeFd());
return pid;
}
+
// ================================================================================
const char** varargs(const char* first, va_list rest) {
va_list copied_rest;
@@ -101,3 +102,11 @@
ret[numOfArgs] = NULL;
return ret;
}
+
+// ================================================================================
+const uint64_t NANOS_PER_SEC = 1000000000;
+uint64_t Nanotime() {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return static_cast<uint64_t>(ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec);
+}
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index db7ec82..3f7df91 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -60,4 +60,9 @@
*/
const char** varargs(const char* first, va_list rest);
-#endif // INCIDENTD_UTIL_H
\ No newline at end of file
+/**
+ * Returns the current monotonic clock time in nanoseconds.
+ */
+uint64_t Nanotime();
+
+#endif // INCIDENTD_UTIL_H
diff --git a/cmds/incidentd/testdata/metadata.txt b/cmds/incidentd/testdata/metadata.txt
new file mode 100644
index 0000000..cb79a3d
--- /dev/null
+++ b/cmds/incidentd/testdata/metadata.txt
Binary files differ
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index 955dbac..42d94f0 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -191,7 +191,7 @@
reporter->batch.add(r);
ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport(&size));
- auto metadata = reporter->batch.metadata();
+ IncidentMetadata metadata = reporter->batch.metadata();
EXPECT_EQ(IncidentMetadata_Destination_EXPLICIT, metadata.dest());
EXPECT_EQ(1, metadata.request_size());
EXPECT_TRUE(metadata.use_dropbox());
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 1528224..55192d0 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -48,6 +48,15 @@
public:
virtual void SetUp() override { ASSERT_NE(tf.fd, -1); }
+ void printDebugString(std::string s) {
+ fprintf(stderr, "size: %zu\n", s.length());
+ for (size_t i = 0; i < s.length(); i++) {
+ char c = s[i];
+ fprintf(stderr, "\\x%x", c);
+ }
+ fprintf(stderr, "\n");
+ }
+
protected:
TemporaryFile tf;
ReportRequestSet requests;
@@ -103,14 +112,18 @@
TEST_F(SectionTest, MetadataSection) {
MetadataSection ms;
+ const std::string testFile = kTestDataPath + "metadata.txt";
+ std::string expect;
+ ASSERT_TRUE(ReadFileToString(testFile, &expect));
requests.setMainFd(STDOUT_FILENO);
+ requests.setMainDest(android::os::DEST_LOCAL);
requests.sectionStats(1)->set_success(true);
CaptureStdout();
ASSERT_EQ(NO_ERROR, ms.Execute(&requests));
- EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b(\x1"
- "2\x4\b\x1\x10\x1"));
+ // Notice message_lite.h ParseFromString doesn't work so we just match the bytes directly.
+ EXPECT_THAT(GetCapturedStdout(), StrEq(expect));
}
TEST_F(SectionTest, FileSection) {
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 8ecb538..7f0a26c 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -40,10 +40,6 @@
src/external/SubsystemSleepStatePuller.cpp \
src/external/ResourceHealthManagerPuller.cpp \
src/external/ResourceThermalManagerPuller.cpp \
- src/external/CpuTimePerUidPuller.cpp \
- src/external/CpuTimePerUidFreqPuller.cpp \
- src/external/KernelUidCpuActiveTimeReader.cpp \
- src/external/KernelUidCpuClusterTimeReader.cpp \
src/external/StatsPullerManagerImpl.cpp \
src/external/puller_util.cpp \
src/logd/LogEvent.cpp \
@@ -203,7 +199,9 @@
tests/e2e/MetricConditionLink_e2e_test.cpp \
tests/e2e/Attribution_e2e_test.cpp \
tests/e2e/GaugeMetric_e2e_test.cpp \
- tests/e2e/DimensionInCondition_e2e_test.cpp
+ tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \
+ tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp \
+ tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
LOCAL_STATIC_LIBRARIES := \
$(statsd_common_static_libraries) \
@@ -251,11 +249,32 @@
LOCAL_MODULE := statsd_benchmark
LOCAL_SRC_FILES := $(statsd_common_src) \
+ src/atom_field_options.proto \
+ src/atoms.proto \
+ src/stats_log.proto \
benchmark/main.cpp \
benchmark/hello_world_benchmark.cpp \
benchmark/log_event_benchmark.cpp \
benchmark/stats_write_benchmark.cpp \
- benchmark/filter_value_benchmark.cpp
+ benchmark/filter_value_benchmark.cpp \
+ benchmark/get_dimensions_for_condition_benchmark.cpp \
+ benchmark/metric_util.cpp \
+ benchmark/duration_metric_benchmark.cpp
+
+LOCAL_STATIC_LIBRARIES := \
+ $(statsd_common_static_libraries)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := full
+
+LOCAL_PROTOC_FLAGS := \
+ -Iexternal/protobuf/src
+
+LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries) \
+ libprotobuf-cpp-full
+
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ platformprotoslite
LOCAL_C_INCLUDES := $(statsd_common_c_includes)
@@ -289,4 +308,4 @@
statsd_common_shared_libraries:=
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index 362d411..1315750 100644
--- a/cmds/statsd/OWNERS
+++ b/cmds/statsd/OWNERS
@@ -1,6 +1,11 @@
bookatz@google.com
+cjyu@google.com
+dwchen@google.com
jinyithu@google.com
+joeo@google.com
kwekua@google.com
+singhtejinder@google.com
stlafon@google.com
yaochen@google.com
yanglu@google.com
+yro@google.com
diff --git a/cmds/statsd/benchmark/duration_metric_benchmark.cpp b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
new file mode 100644
index 0000000..2631009
--- /dev/null
+++ b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#include <vector>
+#include "benchmark/benchmark.h"
+#include "FieldValue.h"
+#include "HashableDimensionKey.h"
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+#include "metric_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::vector;
+
+static StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
+ DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
+ {Position::FIRST});
+ if (addExtraDimensionInCondition) {
+ syncDimension->add_child()->set_field(2 /* name field*/);
+ }
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = screenIsOffPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+ auto combinationPredicate = config.add_predicate();
+ combinationPredicate->set_id(StringToId("CombinationPredicate"));
+ combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
+ addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
+ auto dimensionWhat = metric->mutable_dimensions_in_what();
+ dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(2); // job name field.
+ *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+static StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
+ DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *dimensions = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ if (addExtraDimensionInCondition) {
+ syncDimension->add_child()->set_field(2 /* name field*/);
+ }
+
+ auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = screenIsOffPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+ auto combinationPredicate = config.add_predicate();
+ combinationPredicate->set_id(StringToId("CombinationPredicate"));
+ combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
+ addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
+ *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+
+ auto links = metric->add_links();
+ links->set_condition(isSyncingPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+static void BM_DurationMetricNoLink(benchmark::State& state) {
+ ConfigKey cfgKey;
+ auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
+ DurationMetric::SUM, false);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 11));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 40));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 102));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 450));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 650));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 100));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + bucketSizeNs + 640));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 650));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 10));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 200));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 300));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 401));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ while (state.KeepRunning()) {
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ }
+}
+
+BENCHMARK(BM_DurationMetricNoLink);
+
+
+static void BM_DurationMetricLink(benchmark::State& state) {
+ ConfigKey cfgKey;
+ auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
+ DurationMetric::SUM, false);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions3 = {
+ CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 55));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 120));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 121));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 450));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 501));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 100));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",
+ bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(
+ CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs - 2));
+ events.push_back(
+ CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 110));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 300));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 550));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 800));
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs + 700));
+ sortLogEventsByTimestamp(&events);
+
+ while (state.KeepRunning()) {
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ }
+}
+
+BENCHMARK(BM_DurationMetricLink);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp
index b9ddf36..66c4def 100644
--- a/cmds/statsd/benchmark/filter_value_benchmark.cpp
+++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp
@@ -18,6 +18,7 @@
#include "FieldValue.h"
#include "HashableDimensionKey.h"
#include "logd/LogEvent.h"
+#include "stats_log_util.h"
namespace android {
namespace os {
@@ -25,17 +26,29 @@
using std::vector;
+static void createLogEventAndMatcher(LogEvent* event, FieldMatcher *field_matcher) {
+ AttributionNodeInternal node;
+ node.set_uid(100);
+ node.set_tag("LOCATION");
+
+ std::vector<AttributionNodeInternal> nodes = {node, node};
+ event->write(nodes);
+ event->write(3.2f);
+ event->write("LOCATION");
+ event->write((int64_t)990);
+ event->init();
+
+ field_matcher->set_field(1);
+ auto child = field_matcher->add_child();
+ child->set_field(1);
+ child->set_position(FIRST);
+ child->add_child()->set_field(1);
+}
+
static void BM_FilterValue(benchmark::State& state) {
LogEvent event(1, 100000);
- event.write(3.2f);
- event.write("LOCATION");
- event.write((int64_t)990);
- event.init();
-
FieldMatcher field_matcher;
- field_matcher.set_field(1);
- field_matcher.add_child()->set_field(2);
- field_matcher.add_child()->set_field(3);
+ createLogEventAndMatcher(&event, &field_matcher);
std::vector<Matcher> matchers;
translateFieldMatcher(field_matcher, &matchers);
@@ -48,6 +61,22 @@
BENCHMARK(BM_FilterValue);
+static void BM_FilterValue2(benchmark::State& state) {
+ LogEvent event(1, 100000);
+ FieldMatcher field_matcher;
+ createLogEventAndMatcher(&event, &field_matcher);
+
+ std::vector<Matcher> matchers;
+ translateFieldMatcher(field_matcher, &matchers);
+
+ while (state.KeepRunning()) {
+ HashableDimensionKey output;
+ filterValues(matchers, event.getValues(), &output);
+ }
+}
+
+BENCHMARK(BM_FilterValue2);
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
new file mode 100644
index 0000000..2a4403e
--- /dev/null
+++ b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#include <vector>
+#include "benchmark/benchmark.h"
+#include "FieldValue.h"
+#include "HashableDimensionKey.h"
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::vector;
+
+static void createLogEventAndLink(LogEvent* event, Metric2Condition *link) {
+ AttributionNodeInternal node;
+ node.set_uid(100);
+ node.set_tag("LOCATION");
+
+ std::vector<AttributionNodeInternal> nodes = {node, node};
+ event->write(nodes);
+ event->write(3.2f);
+ event->write("LOCATION");
+ event->write((int64_t)990);
+ event->init();
+
+ link->conditionId = 1;
+
+ FieldMatcher field_matcher;
+ field_matcher.set_field(event->GetTagId());
+ auto child = field_matcher.add_child();
+ child->set_field(1);
+ child->set_position(FIRST);
+ child->add_child()->set_field(1);
+
+ translateFieldMatcher(field_matcher, &link->metricFields);
+ field_matcher.set_field(event->GetTagId() + 1);
+ translateFieldMatcher(field_matcher, &link->conditionFields);
+}
+
+static void BM_GetDimensionInCondition(benchmark::State& state) {
+ Metric2Condition link;
+ LogEvent event(1, 100000);
+ createLogEventAndLink(&event, &link);
+
+ while (state.KeepRunning()) {
+ HashableDimensionKey output;
+ getDimensionForCondition(event.getValues(), link, &output);
+ }
+}
+
+BENCHMARK(BM_GetDimensionInCondition);
+
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
new file mode 100644
index 0000000..b67764b
--- /dev/null
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -0,0 +1,394 @@
+// 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.
+
+#include "metric_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(atomId);
+ return atom_matcher;
+}
+
+AtomMatcher CreateScheduledJobStateChangedAtomMatcher(const string& name,
+ ScheduledJobStateChanged::State state) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
+ field_value_matcher->set_field(3); // State field.
+ field_value_matcher->set_eq_int(state);
+ return atom_matcher;
+}
+
+AtomMatcher CreateStartScheduledJobAtomMatcher() {
+ return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobStart",
+ ScheduledJobStateChanged::STARTED);
+}
+
+AtomMatcher CreateFinishScheduledJobAtomMatcher() {
+ return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobFinish",
+ ScheduledJobStateChanged::FINISHED);
+}
+
+AtomMatcher CreateScreenBrightnessChangedAtomMatcher() {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId("ScreenBrightnessChanged"));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::SCREEN_BRIGHTNESS_CHANGED);
+ return atom_matcher;
+}
+
+AtomMatcher CreateUidProcessStateChangedAtomMatcher() {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId("UidProcessStateChanged"));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::UID_PROCESS_STATE_CHANGED);
+ return atom_matcher;
+}
+
+AtomMatcher CreateWakelockStateChangedAtomMatcher(const string& name,
+ WakelockStateChanged::State state) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::WAKELOCK_STATE_CHANGED);
+ auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
+ field_value_matcher->set_field(4); // State field.
+ field_value_matcher->set_eq_int(state);
+ return atom_matcher;
+}
+
+AtomMatcher CreateAcquireWakelockAtomMatcher() {
+ return CreateWakelockStateChangedAtomMatcher("AcquireWakelock", WakelockStateChanged::ACQUIRE);
+}
+
+AtomMatcher CreateReleaseWakelockAtomMatcher() {
+ return CreateWakelockStateChangedAtomMatcher("ReleaseWakelock", WakelockStateChanged::RELEASE);
+}
+
+AtomMatcher CreateScreenStateChangedAtomMatcher(
+ const string& name, android::view::DisplayStateEnum state) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::SCREEN_STATE_CHANGED);
+ auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
+ field_value_matcher->set_field(1); // State field.
+ field_value_matcher->set_eq_int(state);
+ return atom_matcher;
+}
+
+AtomMatcher CreateScreenTurnedOnAtomMatcher() {
+ return CreateScreenStateChangedAtomMatcher("ScreenTurnedOn",
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+}
+
+AtomMatcher CreateScreenTurnedOffAtomMatcher() {
+ return CreateScreenStateChangedAtomMatcher("ScreenTurnedOff",
+ ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+}
+
+AtomMatcher CreateSyncStateChangedAtomMatcher(
+ const string& name, SyncStateChanged::State state) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::SYNC_STATE_CHANGED);
+ auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
+ field_value_matcher->set_field(3); // State field.
+ field_value_matcher->set_eq_int(state);
+ return atom_matcher;
+}
+
+AtomMatcher CreateSyncStartAtomMatcher() {
+ return CreateSyncStateChangedAtomMatcher("SyncStart", SyncStateChanged::ON);
+}
+
+AtomMatcher CreateSyncEndAtomMatcher() {
+ return CreateSyncStateChangedAtomMatcher("SyncEnd", SyncStateChanged::OFF);
+}
+
+AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
+ const string& name, ActivityForegroundStateChanged::Activity activity) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+ auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
+ field_value_matcher->set_field(4); // Activity field.
+ field_value_matcher->set_eq_int(activity);
+ return atom_matcher;
+}
+
+AtomMatcher CreateMoveToBackgroundAtomMatcher() {
+ return CreateActivityForegroundStateChangedAtomMatcher(
+ "MoveToBackground", ActivityForegroundStateChanged::MOVE_TO_BACKGROUND);
+}
+
+AtomMatcher CreateMoveToForegroundAtomMatcher() {
+ return CreateActivityForegroundStateChangedAtomMatcher(
+ "MoveToForeground", ActivityForegroundStateChanged::MOVE_TO_FOREGROUND);
+}
+
+Predicate CreateScheduledJobPredicate() {
+ Predicate predicate;
+ predicate.set_id(StringToId("ScheduledJobRunningPredicate"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("ScheduledJobStart"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ScheduledJobFinish"));
+ return predicate;
+}
+
+Predicate CreateBatterySaverModePredicate() {
+ Predicate predicate;
+ predicate.set_id(StringToId("BatterySaverIsOn"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("BatterySaverModeStart"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("BatterySaverModeStop"));
+ return predicate;
+}
+
+Predicate CreateScreenIsOnPredicate() {
+ Predicate predicate;
+ predicate.set_id(StringToId("ScreenIsOn"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOn"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOff"));
+ return predicate;
+}
+
+Predicate CreateScreenIsOffPredicate() {
+ Predicate predicate;
+ predicate.set_id(1111123);
+ predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOff"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOn"));
+ return predicate;
+}
+
+Predicate CreateHoldingWakelockPredicate() {
+ Predicate predicate;
+ predicate.set_id(StringToId("HoldingWakelock"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("AcquireWakelock"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ReleaseWakelock"));
+ return predicate;
+}
+
+Predicate CreateIsSyncingPredicate() {
+ Predicate predicate;
+ predicate.set_id(33333333333333);
+ predicate.mutable_simple_predicate()->set_start(StringToId("SyncStart"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("SyncEnd"));
+ return predicate;
+}
+
+Predicate CreateIsInBackgroundPredicate() {
+ Predicate predicate;
+ predicate.set_id(StringToId("IsInBackground"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("MoveToBackground"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("MoveToForeground"));
+ return predicate;
+}
+
+void addPredicateToPredicateCombination(const Predicate& predicate,
+ Predicate* combinationPredicate) {
+ combinationPredicate->mutable_combination()->add_predicate(predicate.id());
+}
+
+FieldMatcher CreateAttributionUidDimensions(const int atomId,
+ const std::vector<Position>& positions) {
+ FieldMatcher dimensions;
+ dimensions.set_field(atomId);
+ for (const auto position : positions) {
+ auto child = dimensions.add_child();
+ child->set_field(1);
+ child->set_position(position);
+ child->add_child()->set_field(1);
+ }
+ return dimensions;
+}
+
+FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId,
+ const std::vector<Position>& positions) {
+ FieldMatcher dimensions;
+ dimensions.set_field(atomId);
+ for (const auto position : positions) {
+ auto child = dimensions.add_child();
+ child->set_field(1);
+ child->set_position(position);
+ child->add_child()->set_field(1);
+ child->add_child()->set_field(2);
+ }
+ return dimensions;
+}
+
+FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields) {
+ FieldMatcher dimensions;
+ dimensions.set_field(atomId);
+ for (const int field : fields) {
+ dimensions.add_child()->set_field(field);
+ }
+ return dimensions;
+}
+
+std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
+ const android::view::DisplayStateEnum state, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::SCREEN_STATE_CHANGED, timestampNs);
+ event->write(state);
+ event->init();
+ return event;
+}
+
+std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
+ int level, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs);
+ (event->write(level));
+ event->init();
+ return event;
+
+}
+
+std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
+ const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
+ event->write(attributions);
+ event->write(jobName);
+ event->write(state);
+ event->init();
+ return event;
+}
+
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs) {
+ return CreateScheduledJobStateChangedEvent(
+ attributions, name, ScheduledJobStateChanged::STARTED, timestampNs);
+}
+
+// Create log event when scheduled job finishes.
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs) {
+ return CreateScheduledJobStateChangedEvent(
+ attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
+ const WakelockStateChanged::State state, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, timestampNs);
+ event->write(attributions);
+ event->write(android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
+ event->write(wakelockName);
+ event->write(state);
+ event->init();
+ return event;
+}
+
+std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
+ uint64_t timestampNs) {
+ return CreateWakelockStateChangedEvent(
+ attributions, wakelockName, WakelockStateChanged::ACQUIRE, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
+ uint64_t timestampNs) {
+ return CreateWakelockStateChangedEvent(
+ attributions, wakelockName, WakelockStateChanged::RELEASE, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
+ const int uid, const ActivityForegroundStateChanged::Activity activity, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(
+ android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs);
+ event->write(uid);
+ event->write("pkg_name");
+ event->write("class_name");
+ event->write(activity);
+ event->init();
+ return event;
+}
+
+std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) {
+ return CreateActivityForegroundStateChangedEvent(
+ uid, ActivityForegroundStateChanged::MOVE_TO_BACKGROUND, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) {
+ return CreateActivityForegroundStateChangedEvent(
+ uid, ActivityForegroundStateChanged::MOVE_TO_FOREGROUND, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& name,
+ const SyncStateChanged::State state, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::SYNC_STATE_CHANGED, timestampNs);
+ event->write(attributions);
+ event->write(name);
+ event->write(state);
+ event->init();
+ return event;
+}
+
+std::unique_ptr<LogEvent> CreateSyncStartEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& name,
+ uint64_t timestampNs) {
+ return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::ON, timestampNs);
+}
+
+std::unique_ptr<LogEvent> CreateSyncEndEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& name,
+ uint64_t timestampNs) {
+ return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::OFF, timestampNs);
+}
+
+sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
+ const ConfigKey& key) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ sp<StatsLogProcessor> processor = new StatsLogProcessor(
+ uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
+ processor->OnConfigUpdated(key, config);
+ return processor;
+}
+
+AttributionNodeInternal CreateAttribution(const int& uid, const string& tag) {
+ AttributionNodeInternal attribution;
+ attribution.set_uid(uid);
+ attribution.set_tag(tag);
+ return attribution;
+}
+
+void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) {
+ std::sort(events->begin(), events->end(),
+ [](const std::unique_ptr<LogEvent>& a, const std::unique_ptr<LogEvent>& b) {
+ return a->GetElapsedTimestampNs() < b->GetElapsedTimestampNs();
+ });
+}
+
+int64_t StringToId(const string& str) {
+ return static_cast<int64_t>(std::hash<std::string>()(str));
+}
+
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/benchmark/metric_util.h b/cmds/statsd/benchmark/metric_util.h
new file mode 100644
index 0000000..9b28d60
--- /dev/null
+++ b/cmds/statsd/benchmark/metric_util.h
@@ -0,0 +1,161 @@
+// 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.
+
+#pragma once
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/StatsLogProcessor.h"
+#include "src/logd/LogEvent.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Create AtomMatcher proto to simply match a specific atom type.
+AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
+
+// Create AtomMatcher proto for scheduled job state changed.
+AtomMatcher CreateScheduledJobStateChangedAtomMatcher();
+
+// Create AtomMatcher proto for starting a scheduled job.
+AtomMatcher CreateStartScheduledJobAtomMatcher();
+
+// Create AtomMatcher proto for a scheduled job is done.
+AtomMatcher CreateFinishScheduledJobAtomMatcher();
+
+// Create AtomMatcher proto for screen brightness state changed.
+AtomMatcher CreateScreenBrightnessChangedAtomMatcher();
+
+// Create AtomMatcher proto for acquiring wakelock.
+AtomMatcher CreateAcquireWakelockAtomMatcher();
+
+// Create AtomMatcher proto for releasing wakelock.
+AtomMatcher CreateReleaseWakelockAtomMatcher() ;
+
+// Create AtomMatcher proto for screen turned on.
+AtomMatcher CreateScreenTurnedOnAtomMatcher();
+
+// Create AtomMatcher proto for screen turned off.
+AtomMatcher CreateScreenTurnedOffAtomMatcher();
+
+// Create AtomMatcher proto for app sync turned on.
+AtomMatcher CreateSyncStartAtomMatcher();
+
+// Create AtomMatcher proto for app sync turned off.
+AtomMatcher CreateSyncEndAtomMatcher();
+
+// Create AtomMatcher proto for app sync moves to background.
+AtomMatcher CreateMoveToBackgroundAtomMatcher();
+
+// Create AtomMatcher proto for app sync moves to foreground.
+AtomMatcher CreateMoveToForegroundAtomMatcher();
+
+// Create Predicate proto for screen is off.
+Predicate CreateScreenIsOffPredicate();
+
+// Create Predicate proto for a running scheduled job.
+Predicate CreateScheduledJobPredicate();
+
+// Create Predicate proto for holding wakelock.
+Predicate CreateHoldingWakelockPredicate();
+
+// Create a Predicate proto for app syncing.
+Predicate CreateIsSyncingPredicate();
+
+// Create a Predicate proto for app is in background.
+Predicate CreateIsInBackgroundPredicate();
+
+// Add a predicate to the predicate combination.
+void addPredicateToPredicateCombination(const Predicate& predicate, Predicate* combination);
+
+// Create dimensions from primitive fields.
+FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields);
+
+// Create dimensions by attribution uid and tag.
+FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId,
+ const std::vector<Position>& positions);
+
+// Create dimensions by attribution uid only.
+FieldMatcher CreateAttributionUidDimensions(const int atomId,
+ const std::vector<Position>& positions);
+
+// Create log event for screen state changed.
+std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
+ const android::view::DisplayStateEnum state, uint64_t timestampNs);
+
+// Create log event for screen brightness state changed.
+std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
+ int level, uint64_t timestampNs);
+
+// Create log event when scheduled job starts.
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs);
+
+// Create log event when scheduled job finishes.
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs);
+
+// Create log event for app moving to background.
+std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
+
+// Create log event for app moving to foreground.
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs);
+
+// Create log event when the app sync starts.
+std::unique_ptr<LogEvent> CreateSyncStartEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& name,
+ uint64_t timestampNs);
+
+// Create log event when the app sync ends.
+std::unique_ptr<LogEvent> CreateSyncEndEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& name,
+ uint64_t timestampNs);
+
+// Create log event when the app sync ends.
+std::unique_ptr<LogEvent> CreateAppCrashEvent(
+ const int uid, uint64_t timestampNs);
+
+// Create log event for acquiring wakelock.
+std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
+ uint64_t timestampNs);
+
+// Create log event for releasing wakelock.
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
+ uint64_t timestampNs);
+
+// Create log event for releasing wakelock.
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
+ int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+
+// Helper function to create an AttributionNodeInternal proto.
+AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
+
+// Create a statsd log event processor upon the start time in seconds, config and key.
+sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
+ const ConfigKey& key);
+
+// Util function to sort the log events by timestamp.
+void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
+
+int64_t StringToId(const string& str);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index b541612..0c9b701 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -205,6 +205,29 @@
}
}
+bool equalDimensions(const std::vector<Matcher>& dimension_a,
+ const std::vector<Matcher>& dimension_b) {
+ bool eq = dimension_a.size() == dimension_b.size();
+ for (size_t i = 0; eq && i < dimension_a.size(); ++i) {
+ if (dimension_b[i] != dimension_a[i]) {
+ eq = false;
+ }
+ }
+ return eq;
+}
+
+bool HasPositionANY(const FieldMatcher& matcher) {
+ if (matcher.has_position() && matcher.position() == Position::ANY) {
+ return true;
+ }
+ for (const auto& child : matcher.child()) {
+ if (HasPositionANY(child)) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 621d0be9..0e3ae06 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -336,11 +336,16 @@
Value mValue;
};
+bool HasPositionANY(const FieldMatcher& matcher);
+
bool isAttributionUidField(const FieldValue& value);
void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
bool isAttributionUidField(const Field& field, const Value& value);
+
+bool equalDimensions(const std::vector<Matcher>& dimension_a,
+ const std::vector<Matcher>& dimension_b);
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index cc706313..d0c8311 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -59,6 +59,33 @@
return JenkinsHashWhiten(hash);
}
+bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
+ HashableDimensionKey* output) {
+ for (size_t i = 0; i < matcherFields.size(); ++i) {
+ const auto& matcher = matcherFields[i];
+ bool found = false;
+ for (const auto& value : values) {
+ // TODO: potential optimization here to break early because all fields are naturally
+ // sorted.
+ if (value.mField.matches(matcher)) {
+ output->addValue(value);
+ output->mutableValue(i)->mField.setTag(value.mField.getTag());
+ output->mutableValue(i)->mField.setField(value.mField.getField() & matcher.mMask);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
+ matcher.mMatcher.getField());
+ return false;
+ }
+ }
+
+ return true;
+}
+
// Filter fields using the matchers and output the results as a HashableDimensionKey.
// Note: HashableDimensionKey is just a wrapper for vector<FieldValue>
bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
@@ -168,22 +195,21 @@
void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
const Metric2Condition& links,
- vector<HashableDimensionKey>* conditionDimension) {
+ HashableDimensionKey* conditionDimension) {
// Get the dimension first by using dimension from what.
filterValues(links.metricFields, eventValues, conditionDimension);
- // Then replace the field with the dimension from condition.
- for (auto& dim : *conditionDimension) {
- size_t count = dim.getValues().size();
- if (count != links.conditionFields.size()) {
- // ALOGE("WTF condition link is bad");
- return;
- }
+ size_t count = conditionDimension->getValues().size();
+ if (count != links.conditionFields.size()) {
+ // ALOGE("WTF condition link is bad");
+ return;
+ }
- for (size_t i = 0; i < count; i++) {
- dim.mutableValue(i)->mField.setField(links.conditionFields[i].mMatcher.getField());
- dim.mutableValue(i)->mField.setTag(links.conditionFields[i].mMatcher.getTag());
- }
+ for (size_t i = 0; i < count; i++) {
+ conditionDimension->mutableValue(i)->mField.setField(
+ links.conditionFields[i].mMatcher.getField());
+ conditionDimension->mutableValue(i)->mField.setTag(
+ links.conditionFields[i].mMatcher.getTag());
}
}
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 57bdf68..4cfed88 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -65,10 +65,6 @@
std::string toString() const;
- inline const char* c_str() const {
- return toString().c_str();
- }
-
bool operator==(const HashableDimensionKey& that) const;
bool operator<(const HashableDimensionKey& that) const;
@@ -104,6 +100,10 @@
return mDimensionKeyInCondition;
}
+ inline void setDimensionKeyInCondition(const HashableDimensionKey& key) {
+ mDimensionKeyInCondition = key;
+ }
+
bool hasDimensionKeyInCondition() const {
return mDimensionKeyInCondition.getValues().size() > 0;
}
@@ -112,9 +112,6 @@
bool operator<(const MetricDimensionKey& that) const;
- inline const char* c_str() const {
- return toString().c_str();
- }
private:
HashableDimensionKey mDimensionKeyInWhat;
HashableDimensionKey mDimensionKeyInCondition;
@@ -134,6 +131,9 @@
*/
bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
std::vector<HashableDimensionKey>* output);
+// This function is used when there is at most one output dimension key. (no ANY matcher)
+bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
+ HashableDimensionKey* output);
/**
* Filter the values from FieldValues using the matchers.
@@ -146,7 +146,7 @@
void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
const Metric2Condition& links,
- std::vector<HashableDimensionKey>* conditionDimension);
+ HashableDimensionKey* conditionDimension);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 3127e94..02d4dc9 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -355,7 +355,6 @@
const ConfigKey& key = pair.first;
vector<uint8_t> data;
onDumpReportLocked(key, getElapsedRealtimeNs(), &data);
- // TODO: Add a guardrail to prevent accumulation of file on disk.
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index a672ab4..8db8200 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -123,10 +123,21 @@
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricNoLink);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricWithLink);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
+
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
+
+
+
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
+
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 280081e..c5dfc44 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -55,18 +55,22 @@
class CompanionDeathRecipient : public IBinder::DeathRecipient {
public:
CompanionDeathRecipient(const sp<AlarmMonitor>& anomalyAlarmMonitor,
- const sp<AlarmMonitor>& periodicAlarmMonitor) :
- mAnomalyAlarmMonitor(anomalyAlarmMonitor),
- mPeriodicAlarmMonitor(periodicAlarmMonitor) {}
+ const sp<AlarmMonitor>& periodicAlarmMonitor,
+ const sp<StatsLogProcessor>& processor)
+ : mAnomalyAlarmMonitor(anomalyAlarmMonitor),
+ mPeriodicAlarmMonitor(periodicAlarmMonitor),
+ mProcessor(processor) {}
virtual void binderDied(const wp<IBinder>& who);
private:
- sp<AlarmMonitor> mAnomalyAlarmMonitor;
- sp<AlarmMonitor> mPeriodicAlarmMonitor;
+ sp<AlarmMonitor> mAnomalyAlarmMonitor;
+ sp<AlarmMonitor> mPeriodicAlarmMonitor;
+ sp<StatsLogProcessor> mProcessor;
};
void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
ALOGW("statscompanion service died");
+ mProcessor->WriteDataToDisk();
mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
mPeriodicAlarmMonitor->setStatsCompanionService(nullptr);
SubscriberReporter::getInstance().setStatsCompanionService(nullptr);
@@ -817,8 +821,9 @@
"statscompanion unavailable despite it contacting statsd!");
}
VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
- IInterface::asBinder(statsCompanion)->linkToDeath(
- new CompanionDeathRecipient(mAnomalyAlarmMonitor, mPeriodicAlarmMonitor));
+ IInterface::asBinder(statsCompanion)
+ ->linkToDeath(new CompanionDeathRecipient(
+ mAnomalyAlarmMonitor, mPeriodicAlarmMonitor, mProcessor));
mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion);
mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion);
SubscriberReporter::getInstance().setStatsCompanionService(statsCompanion);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index e0a1299..02b6124 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -177,11 +177,6 @@
/**
* Print the event log.
*/
- status_t cmd_print_stats_log(FILE* out, const Vector<String8>& args);
-
- /**
- * Print the event log.
- */
status_t cmd_dump_report(FILE* out, FILE* err, const Vector<String8>& args);
/**
@@ -215,10 +210,10 @@
*/
status_t cmd_dump_memory_info(FILE* out);
- /*
+ /*
* Clear all puller cached data
*/
- status_t cmd_clear_puller_cache(FILE* out);
+ status_t cmd_clear_puller_cache(FILE* out);
/**
* Update a configuration.
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 6ee51f3..133f33b 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -59,6 +59,12 @@
}
size_t AnomalyTracker::index(int64_t bucketNum) const {
+ if (bucketNum < 0) {
+ // To support this use-case, we can easily modify index to wrap around. But currently
+ // AnomalyTracker should never need this, so if it happens, it's a bug we should log.
+ // TODO: Audit this.
+ ALOGE("index() was passed a negative bucket number (%lld)!", (long long)bucketNum);
+ }
return bucketNum % mNumOfPastBuckets;
}
@@ -72,9 +78,7 @@
// The past packets are ancient. Empty out old mPastBuckets[i] values and reset
// mSumOverPastBuckets.
if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastBuckets) {
- mPastBuckets.clear();
- mPastBuckets.resize(mNumOfPastBuckets);
- mSumOverPastBuckets.clear();
+ resetStorage();
} else {
for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastBuckets + 1));
i <= latestPastBucketNum - mNumOfPastBuckets; i++) {
@@ -150,7 +154,7 @@
int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key,
const int64_t& bucketNum) const {
- if (mNumOfPastBuckets == 0) {
+ if (mNumOfPastBuckets == 0 || bucketNum < 0) {
return 0;
}
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index e3f493c..d27dee8 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -110,7 +110,7 @@
// Number of past buckets. One less than the total number of buckets needed
// for the anomaly detection (since the current bucket is not in the past).
- int mNumOfPastBuckets;
+ const int mNumOfPastBuckets;
// The existing bucket list.
std::vector<shared_ptr<DimToValMap>> mPastBuckets;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index fa96e11..9bfbd38 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -1489,7 +1489,7 @@
* Note that isolated process uid time should be attributed to host uids.
*/
message CpuTimePerUid {
- optional uint64 uid = 1;
+ optional int32 uid = 1;
optional uint64 user_time_millis = 2;
optional uint64 sys_time_millis = 3;
}
@@ -1500,8 +1500,8 @@
* For each uid, we order the time by descending frequencies.
*/
message CpuTimePerUidFreq {
- optional uint64 uid = 1;
- optional uint64 freq_idx = 2;
+ optional int32 uid = 1;
+ optional uint32 freq_index = 2;
optional uint64 time_millis = 3;
}
@@ -1634,10 +1634,8 @@
* The file contains a monotonically increasing count of time for a single boot.
*/
message CpuActiveTime {
- optional uint64 uid = 1;
- optional uint32 cluster_number = 2;
- optional uint64 idx = 3;
- optional uint64 time_millis = 4;
+ optional int32 uid = 1;
+ optional uint64 time_millis = 2;
}
/**
@@ -1650,8 +1648,8 @@
* The file contains a monotonically increasing count of time for a single boot.
*/
message CpuClusterTime {
- optional uint64 uid = 1;
- optional uint64 idx = 2;
+ optional int32 uid = 1;
+ optional int32 cluster_index = 2;
optional uint64 time_millis = 3;
}
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 13a2b7b..3661d2b 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -91,6 +91,9 @@
if (allConditionTrackers[childIndex]->isSliced()) {
setSliced(true);
+ mSlicedChildren.push_back(childIndex);
+ } else {
+ mUnSlicedChildren.push_back(childIndex);
}
mChildren.push_back(childIndex);
mTrackerIndex.insert(childTracker->getLogTrackerIndex().begin(),
@@ -107,13 +110,19 @@
void CombinationConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
- const std::vector<Matcher>& dimensionFields, vector<ConditionState>& conditionCache,
+ const std::vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
+ vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
// So far, this is fine as there is at most one child having sliced output.
for (const int childIndex : mChildren) {
if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
allConditions[childIndex]->isConditionMet(conditionParameters, allConditions,
- dimensionFields, conditionCache,
+ dimensionFields,
+ isSubOutputDimensionFields,
+ isPartialLink,
+ conditionCache,
dimensionsKeySet);
}
}
@@ -150,7 +159,11 @@
nonSlicedConditionCache[mIndex] = mNonSlicedConditionState;
conditionChangedCache[mIndex] = nonSlicedChanged;
+ mUnSlicedPart = newCondition;
} else {
+ mUnSlicedPart = evaluateCombinationCondition(
+ mUnSlicedChildren, mLogicalOperation, nonSlicedConditionCache);
+
for (const int childIndex : mChildren) {
// If any of the sliced condition in children condition changes, the combination
// condition may be changed too.
@@ -168,13 +181,14 @@
ConditionState CombinationConditionTracker::getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const std::vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
vector<ConditionState> conditionCache(allConditions.size(), ConditionState::kNotEvaluated);
// So far, this is fine as there is at most one child having sliced output.
for (const int childIndex : mChildren) {
conditionCache[childIndex] = conditionCache[childIndex] |
allConditions[childIndex]->getMetConditionDimension(
- allConditions, dimensionFields, dimensionsKeySet);
+ allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet);
}
evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
if (conditionCache[mIndex] == ConditionState::kTrue && dimensionsKeySet.empty()) {
@@ -183,6 +197,18 @@
return conditionCache[mIndex];
}
+bool CombinationConditionTracker::equalOutputDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensions) const {
+ if (mSlicedChildren.size() != 1 ||
+ mSlicedChildren.front() >= (int)allConditions.size() ||
+ mLogicalOperation != LogicalOperation::AND) {
+ return false;
+ }
+ const sp<ConditionTracker>& slicedChild = allConditions.at(mSlicedChildren.front());
+ return slicedChild->equalOutputDimensions(allConditions, dimensions);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 7b8dc6b..481cb20 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -44,12 +44,15 @@
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
std::vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
// Only one child predicate can have dimension.
@@ -63,6 +66,7 @@
}
return nullptr;
}
+
// Only one child predicate can have dimension.
const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
const std::vector<sp<ConditionTracker>>& allConditions) const override {
@@ -75,6 +79,26 @@
return nullptr;
}
+ bool IsSimpleCondition() const override { return false; }
+
+ bool IsChangedDimensionTrackable() const override {
+ return mLogicalOperation == LogicalOperation::AND && mSlicedChildren.size() == 1;
+ }
+
+ bool equalOutputDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensions) const override;
+
+ void getTrueSlicedDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ std::set<HashableDimensionKey>* dimensions) const override {
+ if (mSlicedChildren.size() == 1) {
+ return allConditions[mSlicedChildren.front()]->getTrueSlicedDimensions(
+ allConditions, dimensions);
+ }
+ }
+
+
private:
LogicalOperation mLogicalOperation;
@@ -83,6 +107,10 @@
// map the name to object. We don't want to store smart pointers to children, because it
// increases the risk of circular dependency and memory leak.
std::vector<int> mChildren;
+
+ std::vector<int> mSlicedChildren;
+ std::vector<int> mUnSlicedChildren;
+
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 856a3a0..1f4266b 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -84,18 +84,28 @@
// condition.
// [allConditions]: all condition trackers. This is needed because the condition evaluation is
// done recursively
+ // [dimensionFields]: the needed dimension fields which should be all or subset of the condition
+ // tracker output dimension.
+ // [isSubOutputDimensionFields]: true if the needed dimension fields which is strictly subset of
+ // the condition tracker output dimension.
+ // [isPartialLink]: true if the link specified by 'conditionParameters' contains all the fields
+ // in the condition tracker output dimension.
// [conditionCache]: the cache holding the condition evaluation values.
// [dimensionsKeySet]: the dimensions where the sliced condition is true. For combination
// condition, it assumes that only one child predicate is sliced.
virtual void isConditionMet(
const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields, std::vector<ConditionState>& conditionCache,
+ const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
+ std::vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
virtual ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
// return the list of LogMatchingTracker index that this ConditionTracker uses.
@@ -107,7 +117,7 @@
mSliced = mSliced | sliced;
}
- bool isSliced() const {
+ inline bool isSliced() const {
return mSliced;
}
@@ -116,6 +126,26 @@
virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
+ inline int64_t getConditionId() const {
+ return mConditionId;
+ }
+
+ virtual void getTrueSlicedDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ std::set<HashableDimensionKey>* dimensions) const = 0;
+
+ virtual bool IsChangedDimensionTrackable() const = 0;
+
+ virtual bool IsSimpleCondition() const = 0;
+
+ virtual bool equalOutputDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensions) const = 0;
+
+ inline ConditionState getUnSlicedPartConditionState() const {
+ return mUnSlicedPart;
+ }
+
protected:
const int64_t mConditionId;
@@ -131,6 +161,7 @@
ConditionState mNonSlicedConditionState;
bool mSliced;
+ ConditionState mUnSlicedPart;
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp
index 952b0cc..23a9d37 100644
--- a/cmds/statsd/src/condition/ConditionWizard.cpp
+++ b/cmds/statsd/src/condition/ConditionWizard.cpp
@@ -26,19 +26,24 @@
ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
vector<ConditionState> cache(mAllConditions.size(), ConditionState::kNotEvaluated);
mAllConditions[index]->isConditionMet(
- parameters, mAllConditions, dimensionFields, cache, *dimensionKeySet);
+ parameters, mAllConditions, dimensionFields, isSubOutputDimensionFields, isPartialLink,
+ cache, *dimensionKeySet);
return cache[index];
}
ConditionState ConditionWizard::getMetConditionDimension(
const int index, const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const {
return mAllConditions[index]->getMetConditionDimension(mAllConditions, dimensionFields,
- *dimensionsKeySet);
+ isSubOutputDimensionFields,
+ *dimensionsKeySet);
}
const set<HashableDimensionKey>* ConditionWizard::getChangedToTrueDimensions(
@@ -51,6 +56,30 @@
return mAllConditions[index]->getChangedToFalseDimensions(mAllConditions);
}
+bool ConditionWizard::IsChangedDimensionTrackable(const int index) {
+ if (index >= 0 && index < (int)mAllConditions.size()) {
+ return mAllConditions[index]->IsChangedDimensionTrackable();
+ } else {
+ return false;
+ }
+}
+
+bool ConditionWizard::IsSimpleCondition(const int index) {
+ if (index >= 0 && index < (int)mAllConditions.size()) {
+ return mAllConditions[index]->IsSimpleCondition();
+ } else {
+ return false;
+ }
+}
+
+bool ConditionWizard::equalOutputDimensions(const int index, const vector<Matcher>& dimensions) {
+ if (index >= 0 && index < (int)mAllConditions.size()) {
+ return mAllConditions[index]->equalOutputDimensions(mAllConditions, dimensions);
+ } else {
+ return false;
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index fcfdc2a..a6f88af 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -41,15 +41,30 @@
// the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
virtual ConditionState query(const int conditionIndex, const ConditionKey& conditionParameters,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
std::unordered_set<HashableDimensionKey>* dimensionKeySet);
virtual ConditionState getMetConditionDimension(
const int index, const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const;
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(const int index) const;
virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
const int index) const;
+ bool equalOutputDimensions(const int index, const vector<Matcher>& dimensions);
+
+ bool IsChangedDimensionTrackable(const int index);
+ bool IsSimpleCondition(const int index);
+
+ ConditionState getUnSlicedPartConditionState(const int index) {
+ return mAllConditions[index]->getUnSlicedPartConditionState();
+ }
+ void getTrueSlicedDimensions(const int index,
+ std::set<HashableDimensionKey>* trueDimensions) const {
+ return mAllConditions[index]->getTrueSlicedDimensions(mAllConditions, trueDimensions);
+ }
private:
std::vector<sp<ConditionTracker>> mAllConditions;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 9e27a8b..4913aef 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -34,7 +34,7 @@
const ConfigKey& key, const int64_t& id, const int index,
const SimplePredicate& simplePredicate,
const unordered_map<int64_t, int>& trackerNameIndexMap)
- : ConditionTracker(id, index), mConfigKey(key) {
+ : ConditionTracker(id, index), mConfigKey(key), mContainANYPositionInInternalDimensions(false) {
VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
mCountNesting = simplePredicate.count_nesting();
@@ -80,6 +80,7 @@
mSliced = true;
mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
}
+ mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions());
}
if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
@@ -90,6 +91,10 @@
mNonSlicedConditionState = mInitialValue;
+ if (!mSliced) {
+ mUnSlicedPart = mInitialValue;
+ }
+
mInitialized = true;
}
@@ -109,7 +114,7 @@
void SimpleConditionTracker::dumpState() {
VLOG("%lld DUMP:", (long long)mConditionId);
for (const auto& pair : mSlicedConditionState) {
- VLOG("\t%s : %d", pair.first.c_str(), pair.second);
+ VLOG("\t%s : %d", pair.first.toString().c_str(), pair.second);
}
VLOG("Changed to true keys: \n");
@@ -140,6 +145,9 @@
mInitialValue = ConditionState::kFalse;
mSlicedConditionState.clear();
conditionCache[mIndex] = ConditionState::kFalse;
+ if (!mSliced) {
+ mUnSlicedPart = ConditionState::kFalse;
+ }
}
bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
@@ -154,7 +162,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("Predicate %lld dropping data for dimension key %s",
- (long long)mConditionId, newKey.c_str());
+ (long long)mConditionId, newKey.toString().c_str());
return true;
}
}
@@ -177,13 +185,13 @@
// We get a new output key.
newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
if (matchStart && mInitialValue != ConditionState::kTrue) {
- mSlicedConditionState.insert(std::make_pair(outputKey, 1));
+ mSlicedConditionState[outputKey] = 1;
changed = true;
mLastChangedToTrueDimensions.insert(outputKey);
} else if (mInitialValue != ConditionState::kFalse) {
// it's a stop and we don't have history about it.
// If the default condition is not false, it means this stop is valuable to us.
- mSlicedConditionState.insert(std::make_pair(outputKey, 0));
+ mSlicedConditionState[outputKey] = 0;
mLastChangedToFalseDimensions.insert(outputKey);
changed = true;
}
@@ -226,7 +234,7 @@
// if default condition is false, it means we don't need to keep the false values.
if (mInitialValue == ConditionState::kFalse && startedCount == 0) {
mSlicedConditionState.erase(outputIt);
- VLOG("erase key %s", outputKey.c_str());
+ VLOG("erase key %s", outputKey.toString().c_str());
}
}
}
@@ -238,6 +246,7 @@
(*conditionChangedCache) = changed;
(*conditionCache) = newCondition;
+
VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
conditionChangedCache[mIndex] == true);
}
@@ -294,6 +303,7 @@
conditionCache[mIndex] =
itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
}
+ mUnSlicedPart = conditionCache[mIndex];
}
return;
@@ -305,6 +315,17 @@
if (mOutputDimensions.size() == 0) {
handleConditionEvent(DEFAULT_DIMENSION_KEY, matchedState == 1, &overallState,
&overallChanged);
+ } else if (!mContainANYPositionInInternalDimensions) {
+ HashableDimensionKey outputValue;
+ filterValues(mOutputDimensions, event.getValues(), &outputValue);
+
+ // If this event has multiple nodes in the attribution chain, this log event probably will
+ // generate multiple dimensions. If so, we will find if the condition changes for any
+ // dimension and ask the corresponding metric producer to verify whether the actual sliced
+ // condition has changed or not.
+ // A high level assumption is that a predicate is either sliced or unsliced. We will never
+ // have both sliced and unsliced version of a predicate.
+ handleConditionEvent(outputValue, matchedState == 1, &overallState, &overallChanged);
} else {
std::vector<HashableDimensionKey> outputValues;
filterValues(mOutputDimensions, event.getValues(), &outputValues);
@@ -328,11 +349,17 @@
}
conditionCache[mIndex] = overallState;
conditionChangedCache[mIndex] = overallChanged;
+ if (!mSliced) {
+ mUnSlicedPart = overallState;
+ }
}
void SimpleConditionTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields, vector<ConditionState>& conditionCache,
+ const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
+ vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
@@ -347,7 +374,7 @@
ConditionState conditionState = ConditionState::kNotEvaluated;
if (dimensionFields.size() > 0 && dimensionFields[0].mMatcher.getTag() == mDimensionTag) {
conditionState = conditionState | getMetConditionDimension(
- allConditions, dimensionFields, dimensionsKeySet);
+ allConditions, dimensionFields, isSubOutputDimensionFields, dimensionsKeySet);
} else {
conditionState = conditionState | mInitialValue;
if (!mSliced) {
@@ -362,42 +389,48 @@
conditionCache[mIndex] = conditionState;
return;
}
- std::vector<HashableDimensionKey> defaultKeys = { DEFAULT_DIMENSION_KEY };
- const std::vector<HashableDimensionKey> &keys =
- (pair == conditionParameters.end()) ? defaultKeys : pair->second;
ConditionState conditionState = ConditionState::kNotEvaluated;
- for (size_t i = 0; i < keys.size(); ++i) {
- const HashableDimensionKey& key = keys[i];
+ const HashableDimensionKey& key = pair->second;
+ if (isPartialLink) {
+ // For unseen key, check whether the require dimensions are subset of sliced condition
+ // output.
+ conditionState = conditionState | mInitialValue;
+ for (const auto& slice : mSlicedConditionState) {
+ ConditionState sliceState =
+ slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
+ if (slice.first.contains(key)) {
+ conditionState = conditionState | sliceState;
+ if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
+ if (isSubOutputDimensionFields) {
+ HashableDimensionKey dimensionKey;
+ filterValues(dimensionFields, slice.first.getValues(), &dimensionKey);
+ dimensionsKeySet.insert(dimensionKey);
+ } else {
+ dimensionsKeySet.insert(slice.first);
+ }
+ }
+ }
+ }
+ } else {
auto startedCountIt = mSlicedConditionState.find(key);
+ conditionState = conditionState | mInitialValue;
if (startedCountIt != mSlicedConditionState.end()) {
ConditionState sliceState =
startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
conditionState = conditionState | sliceState;
if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
- vector<HashableDimensionKey> dimensionKeys;
- filterValues(dimensionFields, startedCountIt->first.getValues(), &dimensionKeys);
- dimensionsKeySet.insert(dimensionKeys.begin(), dimensionKeys.end());
- }
- } else {
- // For unseen key, check whether the require dimensions are subset of sliced condition
- // output.
- conditionState = conditionState | mInitialValue;
- for (const auto& slice : mSlicedConditionState) {
- ConditionState sliceState =
- slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
- if (slice.first.contains(key)) {
- conditionState = conditionState | sliceState;
- if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
- vector<HashableDimensionKey> dimensionKeys;
- filterValues(dimensionFields, slice.first.getValues(), &dimensionKeys);
-
- dimensionsKeySet.insert(dimensionKeys.begin(), dimensionKeys.end());
- }
- }
+ if (isSubOutputDimensionFields) {
+ HashableDimensionKey dimensionKey;
+ filterValues(dimensionFields, startedCountIt->first.getValues(), &dimensionKey);
+ dimensionsKeySet.insert(dimensionKey);
+ } else {
+ dimensionsKeySet.insert(startedCountIt->first);
}
}
}
+
+ }
conditionCache[mIndex] = conditionState;
VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
}
@@ -405,6 +438,7 @@
ConditionState SimpleConditionTracker::getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
ConditionState conditionState = mInitialValue;
if (dimensionFields.size() == 0 || mOutputDimensions.size() == 0 ||
@@ -424,10 +458,13 @@
conditionState = conditionState | sliceState;
if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
- vector<HashableDimensionKey> dimensionKeys;
- filterValues(dimensionFields, slice.first.getValues(), &dimensionKeys);
-
- dimensionsKeySet.insert(dimensionKeys.begin(), dimensionKeys.end());
+ if (isSubOutputDimensionFields) {
+ HashableDimensionKey dimensionKey;
+ filterValues(dimensionFields, slice.first.getValues(), &dimensionKey);
+ dimensionsKeySet.insert(dimensionKey);
+ } else {
+ dimensionsKeySet.insert(slice.first);
+ }
}
}
return conditionState;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index e4b72b8..47d1ece 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -49,12 +49,15 @@
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
std::vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
@@ -65,6 +68,7 @@
return nullptr;
}
}
+
virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
const std::vector<sp<ConditionTracker>>& allConditions) const {
if (mSliced) {
@@ -74,6 +78,26 @@
}
}
+ void getTrueSlicedDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ std::set<HashableDimensionKey>* dimensions) const override {
+ for (const auto& itr : mSlicedConditionState) {
+ if (itr.second > 0) {
+ dimensions->insert(itr.first);
+ }
+ }
+ }
+
+ bool IsChangedDimensionTrackable() const override { return true; }
+
+ bool IsSimpleCondition() const override { return true; }
+
+ bool equalOutputDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensions) const override {
+ return equalDimensions(mOutputDimensions, dimensions);
+ }
+
private:
const ConfigKey mConfigKey;
// The index of the LogEventMatcher which defines the start.
@@ -92,6 +116,8 @@
std::vector<Matcher> mOutputDimensions;
+ bool mContainANYPositionInInternalDimensions;
+
std::set<HashableDimensionKey> mLastChangedToTrueDimensions;
std::set<HashableDimensionKey> mLastChangedToFalseDimensions;
diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateTracker.cpp
index e479f93..c68875c 100644
--- a/cmds/statsd/src/condition/StateTracker.cpp
+++ b/cmds/statsd/src/condition/StateTracker.cpp
@@ -107,7 +107,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("Predicate %lld dropping data for dimension key %s",
- (long long)mConditionId, newKey.c_str());
+ (long long)mConditionId, newKey.toString().c_str());
return true;
}
}
@@ -181,7 +181,10 @@
void StateTracker::isConditionMet(
const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
- const vector<Matcher>& dimensionFields, vector<ConditionState>& conditionCache,
+ const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
+ vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
@@ -203,20 +206,19 @@
return;
}
- const auto& primaryKeys = pair->second;
+ const auto& primaryKey = pair->second;
conditionCache[mIndex] = mInitialValue;
- for (const auto& primaryKey : primaryKeys) {
- auto it = mSlicedState.find(primaryKey);
- if (it != mSlicedState.end()) {
- conditionCache[mIndex] = ConditionState::kTrue;
- dimensionsKeySet.insert(it->second);
- }
+ auto it = mSlicedState.find(primaryKey);
+ if (it != mSlicedState.end()) {
+ conditionCache[mIndex] = ConditionState::kTrue;
+ dimensionsKeySet.insert(it->second);
}
}
ConditionState StateTracker::getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
if (mSlicedState.size() > 0) {
for (const auto& state : mSlicedState) {
diff --git a/cmds/statsd/src/condition/StateTracker.h b/cmds/statsd/src/condition/StateTracker.h
index 3fe6e60..2bdf98c 100644
--- a/cmds/statsd/src/condition/StateTracker.h
+++ b/cmds/statsd/src/condition/StateTracker.h
@@ -56,6 +56,8 @@
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
+ const bool isPartialLink,
std::vector<ConditionState>& conditionCache,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
@@ -67,6 +69,7 @@
ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensionFields,
+ const bool isSubOutputDimensionFields,
std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
@@ -79,6 +82,24 @@
return &mLastChangedToFalseDimensions;
}
+ bool IsChangedDimensionTrackable() const override { return true; }
+
+ bool IsSimpleCondition() const override { return true; }
+
+ bool equalOutputDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensions) const override {
+ return equalDimensions(mOutputDimensions, dimensions);
+ }
+
+ void getTrueSlicedDimensions(
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ std::set<HashableDimensionKey>* dimensions) const override {
+ for (const auto& itr : mSlicedState) {
+ dimensions->insert(itr.second);
+ }
+ }
+
private:
const ConfigKey mConfigKey;
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
deleted file mode 100644
index d1d9d37..0000000
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ /dev/null
@@ -1,100 +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.
- */
-
-#define DEBUG false // STOPSHIP if true
-#include "Log.h"
-
-#include <fstream>
-#include "external/CpuTimePerUidFreqPuller.h"
-
-#include "../guardrail/StatsdStats.h"
-#include "CpuTimePerUidFreqPuller.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-using std::make_shared;
-using std::shared_ptr;
-using std::ifstream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static const string sProcFile = "/proc/uid_time_in_state";
-static const int kLineBufferSize = 1024;
-
-/**
- * Reads /proc/uid_time_in_state which has the format:
- *
- * uid: [freq1] [freq2] [freq3] ...
- * [uid1]: [time in freq1] [time in freq2] [time in freq3] ...
- * [uid2]: [time in freq1] [time in freq2] [time in freq3] ...
- * ...
- *
- * This provides the times a UID's processes spent executing at each different cpu frequency.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-CpuTimePerUidFreqPuller::CpuTimePerUidFreqPuller()
- : StatsPuller(android::util::CPU_TIME_PER_UID_FREQ) {
-}
-
-bool CpuTimePerUidFreqPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- data->clear();
-
- ifstream fin;
- fin.open(sProcFile);
- if (!fin.good()) {
- VLOG("Failed to read pseudo file %s", sProcFile.c_str());
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
-
- char buf[kLineBufferSize];
- // first line prints the format and frequencies
- fin.getline(buf, kLineBufferSize);
- char* pch;
- while (!fin.eof()) {
- fin.getline(buf, kLineBufferSize);
- pch = strtok(buf, " :");
- if (pch == NULL) break;
- uint64_t uid = std::stoull(pch);
- pch = strtok(NULL, " ");
- uint64_t timeMs;
- int idx = 0;
- do {
- timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ,
- wallClockTimestampNs, elapsedTimestampNs);
- ptr->write(uid);
- ptr->write(idx);
- ptr->write(timeMs);
- ptr->init();
- data->push_back(ptr);
- VLOG("uid %lld, freq idx %d, sys time %lld", (long long)uid, idx, (long long)timeMs);
- idx++;
- pch = strtok(NULL, " ");
- } while (pch != NULL);
- }
- return true;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.h b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.h
deleted file mode 100644
index 6f6c669..0000000
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.h
+++ /dev/null
@@ -1,42 +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.
- */
-
-#pragma once
-
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Reads /proc/uid_cputime/show_uid_stat which has the line format:
- *
- * uid: user_time_micro_seconds system_time_micro_seconds
- *
- * This provides the time a UID's processes spent executing in user-space and kernel-space.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-class CpuTimePerUidFreqPuller : public StatsPuller {
- public:
- CpuTimePerUidFreqPuller();
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
deleted file mode 100644
index 568b8f0..0000000
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ /dev/null
@@ -1,90 +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.
- */
-
-#define DEBUG false // STOPSHIP if true
-#include "Log.h"
-
-#include <fstream>
-#include "external/CpuTimePerUidPuller.h"
-
-#include "CpuTimePerUidPuller.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-using std::make_shared;
-using std::shared_ptr;
-using std::ifstream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static const string sProcFile = "/proc/uid_cputime/show_uid_stat";
-static const int kLineBufferSize = 1024;
-
-/**
- * Reads /proc/uid_cputime/show_uid_stat which has the line format:
- *
- * uid: user_time_micro_seconds system_time_micro_seconds power_in_milli-amp-micro_seconds
- *
- * This provides the time a UID's processes spent executing in user-space and kernel-space.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-CpuTimePerUidPuller::CpuTimePerUidPuller() : StatsPuller(android::util::CPU_TIME_PER_UID) {
-}
-
-bool CpuTimePerUidPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- data->clear();
-
- ifstream fin;
- fin.open(sProcFile);
- if (!fin.good()) {
- VLOG("Failed to read pseudo file %s", sProcFile.c_str());
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
- char buf[kLineBufferSize];
- char* pch;
- while (!fin.eof()) {
- fin.getline(buf, kLineBufferSize);
- pch = strtok(buf, " :");
- if (pch == NULL) break;
- uint64_t uid = std::stoull(pch);
- pch = strtok(buf, " ");
- uint64_t userTimeMs = std::stoull(pch);
- pch = strtok(buf, " ");
- uint64_t sysTimeMs = std::stoull(pch);
-
- auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID,
- wallClockTimestampNs, elapsedTimestampNs);
- ptr->write(uid);
- ptr->write(userTimeMs);
- ptr->write(sysTimeMs);
- ptr->init();
- data->push_back(ptr);
- VLOG("uid %lld, user time %lld, sys time %lld", (long long)uid, (long long)userTimeMs,
- (long long)sysTimeMs);
- }
- return true;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.h b/cmds/statsd/src/external/CpuTimePerUidPuller.h
deleted file mode 100644
index d0d39d0..0000000
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.h
+++ /dev/null
@@ -1,42 +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.
- */
-
-#pragma once
-
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Reads /proc/uid_cputime/show_uid_stat which has the line format:
- *
- * uid: user_time_micro_seconds system_time_micro_seconds
- *
- * This provides the time a UID's processes spent executing in user-space and kernel-space.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-class CpuTimePerUidPuller : public StatsPuller {
- public:
- CpuTimePerUidPuller();
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
deleted file mode 100644
index 0b545cc..0000000
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#define DEBUG false // STOPSHIP if true
-#include "Log.h"
-
-#include <fstream>
-
-#include "KernelUidCpuActiveTimeReader.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-using std::make_shared;
-using std::shared_ptr;
-using std::ifstream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static const string sProcFile = "/proc/uid_concurrent_active_time";
-static const int kLineBufferSize = 1024;
-
-/**
- * Reads /proc/uid_concurrent_active_time which has the format:
- * active: X (X is # cores)
- * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
- * [uid1]: [time-0] [time-1] [time-2] ... ...
- * ...
- * Time-N means the CPU time a UID spent running concurrently with N other processes.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-KernelUidCpuActiveTimeReader::KernelUidCpuActiveTimeReader() : StatsPuller(android::util::CPU_ACTIVE_TIME) {
-}
-
-bool KernelUidCpuActiveTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- data->clear();
-
- ifstream fin;
- fin.open(sProcFile);
- if (!fin.good()) {
- VLOG("Failed to read pseudo file %s", sProcFile.c_str());
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
-
- char buf[kLineBufferSize];
- char* pch;
- while (!fin.eof()) {
- fin.getline(buf, kLineBufferSize);
- pch = strtok(buf, " :");
- if (pch == NULL) break;
- uint64_t uid = std::stoull(pch);
- pch = strtok(NULL, " ");
- uint64_t timeMs;
- int idx = 0;
- do {
- timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(mTagId, wallClockTimestampNs, elapsedTimestampNs);
- ptr->write(uid);
- ptr->write(idx);
- ptr->write(timeMs);
- ptr->init();
- data->push_back(ptr);
- VLOG("uid %lld, freq idx %d, active time %lld", (long long)uid, idx, (long long)timeMs);
- idx++;
- pch = strtok(NULL, " ");
- } while (pch != NULL);
- }
- return true;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
deleted file mode 100644
index cc80204..0000000
--- a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#define DEBUG false // STOPSHIP if true
-#include "Log.h"
-
-#include <fstream>
-#include "KernelUidCpuClusterTimeReader.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-using std::make_shared;
-using std::shared_ptr;
-using std::ifstream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static const string sProcFile = "/proc/uid_concurrent_policy_time";
-static const int kLineBufferSize = 1024;
-
-/**
- * Reads /proc/uid_concurrent_policy_time which has the format:
- * policy0: X policy4: Y (there are X cores on policy0, Y cores on policy4)
- * [uid0]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
- * [uid1]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
- * ...
- * Time-X-Y means the time a UID spent on clusterX running concurrently with Y other processes.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-KernelUidCpuClusterTimeReader::KernelUidCpuClusterTimeReader() : StatsPuller(android::util::CPU_CLUSTER_TIME) {
-}
-
-bool KernelUidCpuClusterTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- data->clear();
-
- ifstream fin;
- fin.open(sProcFile);
- if (!fin.good()) {
- VLOG("Failed to read pseudo file %s", sProcFile.c_str());
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
- char buf[kLineBufferSize];
- char* pch;
- while (!fin.eof()) {
- fin.getline(buf, kLineBufferSize);
- pch = strtok(buf, " :");
- if (pch == NULL) break;
- uint64_t uid = std::stoull(pch);
- pch = strtok(NULL, " ");
- uint64_t timeMs;
- int idx = 0;
- do {
- timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(mTagId, wallClockTimestampNs, elapsedTimestampNs);
- ptr->write(uid);
- ptr->write(idx);
- ptr->write(timeMs);
- ptr->init();
- data->push_back(ptr);
- VLOG("uid %lld, freq idx %d, cluster time %lld", (long long)uid, idx, (long long)timeMs);
- idx++;
- pch = strtok(NULL, " ");
- } while (pch != NULL);
- }
- return true;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h
deleted file mode 100644
index 90236ae..0000000
--- a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#pragma once
-
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Reads /proc/uid_cputime/show_uid_stat which has the line format:
- *
- * uid: user_time_micro_seconds system_time_micro_seconds
- *
- * This provides the time a UID's processes spent executing in user-space and kernel-space.
- * The file contains a monotonically increasing count of time for a single boot.
- */
-class KernelUidCpuClusterTimeReader : public StatsPuller {
- public:
- KernelUidCpuClusterTimeReader();
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 9513cc5..3b0cd34 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -21,6 +21,7 @@
#include "guardrail/StatsdStats.h"
#include "puller_util.h"
#include "stats_log_util.h"
+#include "StatsPullerManagerImpl.h"
namespace android {
namespace os {
@@ -34,11 +35,7 @@
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
StatsPuller::StatsPuller(const int tagId)
: mTagId(tagId) {
- if (StatsdStats::kPullerCooldownMap.find(tagId) == StatsdStats::kPullerCooldownMap.end()) {
- mCoolDownSec = StatsdStats::kDefaultPullerCooldown;
- } else {
- mCoolDownSec = StatsdStats::kPullerCooldownMap[tagId];
- }
+ mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec;
VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec);
}
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 880dfd1..72a00cb 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -21,10 +21,6 @@
#include <cutils/log.h>
#include <algorithm>
#include <climits>
-#include "CpuTimePerUidFreqPuller.h"
-#include "CpuTimePerUidPuller.h"
-#include "KernelUidCpuActiveTimeReader.h"
-#include "KernelUidCpuClusterTimeReader.h"
#include "ResourceHealthManagerPuller.h"
#include "ResourceThermalManagerPuller.h"
#include "StatsCompanionServicePuller.h"
@@ -51,27 +47,19 @@
const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = {
// wifi_bytes_transfer
{android::util::WIFI_BYTES_TRANSFER,
- {{2, 3, 4, 5},
- {},
- 1,
+ {{2, 3, 4, 5}, {}, 1,
new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
// wifi_bytes_transfer_by_fg_bg
{android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
- {{3, 4, 5, 6},
- {2},
- 1,
+ {{3, 4, 5, 6}, {2}, 1,
new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
// mobile_bytes_transfer
{android::util::MOBILE_BYTES_TRANSFER,
- {{2, 3, 4, 5},
- {},
- 1,
+ {{2, 3, 4, 5}, {}, 1,
new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
// mobile_bytes_transfer_by_fg_bg
{android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
- {{3, 4, 5, 6},
- {2},
- 1,
+ {{3, 4, 5, 6}, {2}, 1,
new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
// bluetooth_bytes_transfer
{android::util::BLUETOOTH_BYTES_TRANSFER,
@@ -80,14 +68,26 @@
{android::util::KERNEL_WAKELOCK,
{{}, {}, 1, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
// subsystem_sleep_state
- {android::util::SUBSYSTEM_SLEEP_STATE, {{}, {}, 1, new SubsystemSleepStatePuller()}},
+ {android::util::SUBSYSTEM_SLEEP_STATE,
+ {{}, {}, 1, new SubsystemSleepStatePuller()}},
// cpu_time_per_freq
{android::util::CPU_TIME_PER_FREQ,
{{3}, {2}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
// cpu_time_per_uid
- {android::util::CPU_TIME_PER_UID, {{2, 3}, {}, 1, new CpuTimePerUidPuller()}},
+ {android::util::CPU_TIME_PER_UID,
+ {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
// cpu_time_per_uid_freq
- {android::util::CPU_TIME_PER_UID_FREQ, {{3}, {2}, 1, new CpuTimePerUidFreqPuller()}},
+ // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+ {android::util::CPU_TIME_PER_UID_FREQ,
+ {{4}, {2,3}, 0, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
+ // cpu_active_time
+ // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+ {android::util::CPU_ACTIVE_TIME,
+ {{2}, {}, 0, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
+ // cpu_cluster_time
+ // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+ {android::util::CPU_CLUSTER_TIME,
+ {{3}, {2}, 0, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
// wifi_activity_energy_info
{android::util::WIFI_ACTIVITY_ENERGY_INFO,
{{}, {}, 1, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
@@ -103,10 +103,6 @@
// system_uptime
{android::util::SYSTEM_UPTIME,
{{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
- // cpu_active_time
- {android::util::CPU_ACTIVE_TIME, {{3}, {2}, 1, new KernelUidCpuActiveTimeReader()}},
- // cpu_cluster_time
- {android::util::CPU_CLUSTER_TIME, {{3}, {2}, 1, new KernelUidCpuClusterTimeReader()}},
// disk_space
{android::util::DISK_SPACE,
{{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
@@ -118,7 +114,10 @@
{{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
+ {{4,5,6,7,8},
+ {2,3},
+ 0,
+ new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
// temperature
{android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}};
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index d626d90..c6c4d13 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -91,18 +91,6 @@
const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4;
const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5;
-std::map<int, long> StatsdStats::kPullerCooldownMap = {
- {android::util::KERNEL_WAKELOCK, 1},
- {android::util::WIFI_BYTES_TRANSFER, 1},
- {android::util::MOBILE_BYTES_TRANSFER, 1},
- {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1},
- {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1},
- {android::util::SUBSYSTEM_SLEEP_STATE, 1},
- {android::util::CPU_TIME_PER_FREQ, 1},
- {android::util::CPU_TIME_PER_UID, 1},
- {android::util::CPU_TIME_PER_UID_FREQ, 1},
-};
-
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index c3f4013..d05c91b 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -111,13 +111,6 @@
/* Min period between two checks of byte size per config key in nanoseconds. */
static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
- // Default minimum interval between pulls for an atom. Pullers can return cached values if
- // another pull request happens within this interval.
- static std::map<int, long> kPullerCooldownMap;
-
- // Default cooldown time for a puller
- static const long kDefaultPullerCooldown = 1;
-
// Maximum age (30 days) that files on disk can exist in seconds.
static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index da5ef44..22b2a30 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -71,6 +71,7 @@
if (metric.has_dimensions_in_what()) {
translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
if (metric.has_dimensions_in_condition()) {
@@ -113,7 +114,7 @@
for (const auto& counter : mPastBuckets) {
const MetricDimensionKey& dimensionKey = counter.first;
- VLOG(" dimension key %s", dimensionKey.c_str());
+ VLOG(" dimension key %s", dimensionKey.toString().c_str());
uint64_t wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
@@ -176,7 +177,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("CountMetric %lld dropping data for dimension key %s",
- (long long)mMetricId, newKey.c_str());
+ (long long)mMetricId, newKey.toString().c_str());
return true;
}
}
@@ -218,7 +219,7 @@
countWholeBucket);
}
- VLOG("metric %lld %s->%lld", (long long)mMetricId, eventKey.c_str(),
+ VLOG("metric %lld %s->%lld", (long long)mMetricId, eventKey.toString().c_str(),
(long long)(*mCurrentSlicedCounter)[eventKey]);
}
@@ -253,7 +254,8 @@
info.mCount = counter.second;
auto& bucketList = mPastBuckets[counter.first];
bucketList.push_back(info);
- VLOG("metric %lld, dump key value: %s -> %lld", (long long)mMetricId, counter.first.c_str(),
+ VLOG("metric %lld, dump key value: %s -> %lld", (long long)mMetricId,
+ counter.first.toString().c_str(),
(long long)counter.second);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 29a892d..bc09683 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -67,7 +67,8 @@
mStartIndex(startIndex),
mStopIndex(stopIndex),
mStopAllIndex(stopAllIndex),
- mNested(nesting) {
+ mNested(nesting),
+ mContainANYPositionInInternalDimensions(false) {
// TODO: The following boiler plate code appears in all MetricProducers, but we can't abstract
// them in the base class, because the proto generated CountMetric, and DurationMetric are
// not related. Maybe we should add a template in the future??
@@ -80,10 +81,12 @@
if (metric.has_dimensions_in_what()) {
translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
if (internalDimensions.has_field()) {
translateFieldMatcher(internalDimensions, &mInternalDimensions);
+ mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions);
}
if (metric.has_dimensions_in_condition()) {
@@ -100,19 +103,18 @@
}
}
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
+ mUnSlicedPartCondition = ConditionState::kUnknown;
- if (mDimensionsInWhat.size() == mInternalDimensions.size()) {
- bool mUseWhatDimensionAsInternalDimension = true;
- for (size_t i = 0; mUseWhatDimensionAsInternalDimension &&
- i < mDimensionsInWhat.size(); ++i) {
- if (mDimensionsInWhat[i] != mInternalDimensions[i]) {
- mUseWhatDimensionAsInternalDimension = false;
- }
+ mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
+ if (mWizard != nullptr && mConditionTrackerIndex >= 0) {
+ mSameConditionDimensionsInTracker =
+ mWizard->equalOutputDimensions(mConditionTrackerIndex, mDimensionsInCondition);
+ if (mMetric2ConditionLinks.size() == 1) {
+ mHasLinksToAllConditionDimensionsInTracker =
+ mWizard->equalOutputDimensions(mConditionTrackerIndex,
+ mMetric2ConditionLinks.begin()->conditionFields);
}
- } else {
- mUseWhatDimensionAsInternalDimension = false;
}
-
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -124,6 +126,13 @@
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
std::lock_guard<std::mutex> lock(mMutex);
+ if (mAggregationType == DurationMetric_AggregationType_SUM) {
+ if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
+ ALOGW("invalid alert for SUM: threshold (%f) > possible recordable value (%d x %lld)",
+ alert.trigger_if_sum_gt(), alert.num_buckets(), (long long)mBucketSizeNs);
+ return nullptr;
+ }
+ }
sp<DurationAnomalyTracker> anomalyTracker =
new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
if (anomalyTracker != nullptr) {
@@ -139,12 +148,171 @@
return make_unique<OringDurationTracker>(
mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
- mStartTimeNs, mBucketSizeNs, mConditionSliced, mAnomalyTrackers);
+ mStartTimeNs, mBucketSizeNs, mConditionSliced,
+ mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
case DurationMetric_AggregationType_MAX_SPARSE:
return make_unique<MaxDurationTracker>(
mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
- mStartTimeNs, mBucketSizeNs, mConditionSliced, mAnomalyTrackers);
+ mStartTimeNs, mBucketSizeNs, mConditionSliced,
+ mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
+ }
+}
+
+// SlicedConditionChange optimization case 1:
+// 1. If combination condition, logical operation is AND, only one sliced child predicate.
+// 2. No condition in dimension
+// 3. The links covers all dimension fields in the sliced child condition predicate.
+void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(const uint64_t eventTime) {
+ if (mMetric2ConditionLinks.size() != 1 ||
+ !mHasLinksToAllConditionDimensionsInTracker ||
+ !mDimensionsInCondition.empty()) {
+ return;
+ }
+
+ bool currentUnSlicedPartCondition = true;
+ if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
+ ConditionState unslicedPartState =
+ mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
+ // When the unsliced part is still false, return directly.
+ if (mUnSlicedPartCondition == ConditionState::kFalse &&
+ unslicedPartState == ConditionState::kFalse) {
+ return;
+ }
+ mUnSlicedPartCondition = unslicedPartState;
+ currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
+ }
+
+ auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
+ auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
+
+ // The condition change is from the unsliced predicates.
+ // We need to find out the true dimensions from the sliced predicate and flip their condition
+ // state based on the new unsliced condition state.
+ if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
+ (dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
+ std::set<HashableDimensionKey> trueConditionDimensions;
+ mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ HashableDimensionKey linkedConditionDimensionKey;
+ getDimensionForCondition(whatIt.first.getValues(),
+ mMetric2ConditionLinks[0],
+ &linkedConditionDimensionKey);
+ if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
+ trueConditionDimensions.end()) {
+ for (auto& condIt : whatIt.second) {
+ condIt.second->onConditionChanged(
+ currentUnSlicedPartCondition, eventTime);
+ }
+ }
+ }
+ } else {
+ // Handle the condition change from the sliced predicate.
+ if (currentUnSlicedPartCondition) {
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ HashableDimensionKey linkedConditionDimensionKey;
+ getDimensionForCondition(whatIt.first.getValues(),
+ mMetric2ConditionLinks[0],
+ &linkedConditionDimensionKey);
+ if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
+ dimensionsChangedToTrue->end()) {
+ for (auto& condIt : whatIt.second) {
+ condIt.second->onConditionChanged(true, eventTime);
+ }
+ }
+ if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
+ dimensionsChangedToFalse->end()) {
+ for (auto& condIt : whatIt.second) {
+ condIt.second->onConditionChanged(false, eventTime);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// SlicedConditionChange optimization case 2:
+// 1. If combination condition, logical operation is AND, only one sliced child predicate.
+// 2. Has dimensions_in_condition and it equals to the output dimensions of the sliced predicate.
+void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt2(const uint64_t eventTime) {
+ if (mMetric2ConditionLinks.size() > 1 || !mSameConditionDimensionsInTracker) {
+ return;
+ }
+
+ auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
+ auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
+
+ bool currentUnSlicedPartCondition = true;
+ if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
+ ConditionState unslicedPartState =
+ mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
+ // When the unsliced part is still false, return directly.
+ if (mUnSlicedPartCondition == ConditionState::kFalse &&
+ unslicedPartState == ConditionState::kFalse) {
+ return;
+ }
+ mUnSlicedPartCondition = unslicedPartState;
+ currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
+ }
+
+ const std::set<HashableDimensionKey>* trueDimensionsToProcess = nullptr;
+ const std::set<HashableDimensionKey>* falseDimensionsToProcess = nullptr;
+
+ std::set<HashableDimensionKey> currentTrueConditionDimensions;
+ if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
+ (dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
+ mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, ¤tTrueConditionDimensions);
+ trueDimensionsToProcess = ¤tTrueConditionDimensions;
+ } else if (currentUnSlicedPartCondition) {
+ // Handles the condition change from the sliced predicate. If the unsliced condition state
+ // is not true, not need to do anything.
+ trueDimensionsToProcess = dimensionsChangedToTrue;
+ falseDimensionsToProcess = dimensionsChangedToFalse;
+ }
+
+ if (trueDimensionsToProcess == nullptr && falseDimensionsToProcess == nullptr) {
+ return;
+ }
+
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ if (falseDimensionsToProcess != nullptr) {
+ for (const auto& changedDim : *falseDimensionsToProcess) {
+ auto condIt = whatIt.second.find(changedDim);
+ if (condIt != whatIt.second.end()) {
+ condIt->second->onConditionChanged(false, eventTime);
+ }
+ }
+ }
+ if (trueDimensionsToProcess != nullptr) {
+ HashableDimensionKey linkedConditionDimensionKey;
+ if (!trueDimensionsToProcess->empty() && mMetric2ConditionLinks.size() == 1) {
+ getDimensionForCondition(whatIt.first.getValues(),
+ mMetric2ConditionLinks[0],
+ &linkedConditionDimensionKey);
+ }
+ for (auto& trueDim : *trueDimensionsToProcess) {
+ auto condIt = whatIt.second.find(trueDim);
+ if (condIt != whatIt.second.end()) {
+ condIt->second->onConditionChanged(
+ currentUnSlicedPartCondition, eventTime);
+ } else {
+ if (mMetric2ConditionLinks.size() == 0 ||
+ trueDim.contains(linkedConditionDimensionKey)) {
+ if (!whatIt.second.empty()) {
+ unique_ptr<DurationTracker> newTracker =
+ whatIt.second.begin()->second->clone(eventTime);
+ if (newTracker != nullptr) {
+ newTracker->setEventKey(
+ MetricDimensionKey(whatIt.first, trueDim));
+ newTracker->onConditionChanged(true, eventTime);
+ whatIt.second[trueDim] = std::move(newTracker);
+ }
+ }
+ }
+ }
+ }
+ }
}
}
@@ -152,6 +320,23 @@
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
flushIfNeededLocked(eventTime);
+ if (!mConditionSliced) {
+ return;
+ }
+
+ bool changeDimTrackable = mWizard->IsChangedDimensionTrackable(mConditionTrackerIndex);
+ if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker &&
+ mDimensionsInCondition.empty()) {
+ onSlicedConditionMayChangeLocked_opt1(eventTime);
+ return;
+ }
+
+ if (changeDimTrackable && mSameConditionDimensionsInTracker &&
+ mMetric2ConditionLinks.size() <= 1) {
+ onSlicedConditionMayChangeLocked_opt2(eventTime);
+ return;
+ }
+
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (auto& pair : whatIt.second) {
@@ -166,6 +351,7 @@
if (mMetric2ConditionLinks.empty()) {
std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
+ !mSameConditionDimensionsInTracker,
&conditionDimensionsKeySet);
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (const auto& pair : whatIt.second) {
@@ -177,9 +363,12 @@
if (!whatIt.second.empty()) {
unique_ptr<DurationTracker> newTracker =
whatIt.second.begin()->second->clone(eventTime);
- newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension));
- newTracker->onSlicedConditionMayChange(eventTime);
- whatIt.second[conditionDimension] = std::move(newTracker);
+ if (newTracker != nullptr) {
+ newTracker->setEventKey(MetricDimensionKey(
+ whatIt.first, conditionDimension));
+ newTracker->onSlicedConditionMayChange(eventTime);
+ whatIt.second[conditionDimension] = std::move(newTracker);
+ }
}
}
}
@@ -192,15 +381,20 @@
}
std::unordered_set<HashableDimensionKey> conditionDimensionsKeys;
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
&conditionDimensionsKeys);
for (const auto& conditionDimension : conditionDimensionsKeys) {
if (!whatIt.second.empty() &&
whatIt.second.find(conditionDimension) == whatIt.second.end()) {
auto newTracker = whatIt.second.begin()->second->clone(eventTime);
- newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension));
- newTracker->onSlicedConditionMayChange(eventTime);
- whatIt.second[conditionDimension] = std::move(newTracker);
+ if (newTracker != nullptr) {
+ newTracker->setEventKey(
+ MetricDimensionKey(whatIt.first, conditionDimension));
+ newTracker->onSlicedConditionMayChange(eventTime);
+ whatIt.second[conditionDimension] = std::move(newTracker);
+ }
}
}
}
@@ -241,7 +435,7 @@
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
- VLOG(" dimension key %s", dimensionKey.c_str());
+ VLOG(" dimension key %s", dimensionKey.toString().c_str());
uint64_t wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
@@ -291,7 +485,8 @@
whatIt != mCurrentSlicedDurationTrackerMap.end();) {
for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str());
+ VLOG("erase bucket for key %s %s",
+ whatIt->first.toString().c_str(), it->first.toString().c_str());
it = whatIt->second.erase(it);
} else {
++it;
@@ -314,7 +509,8 @@
whatIt != mCurrentSlicedDurationTrackerMap.end();) {
for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str());
+ VLOG("erase bucket for key %s %s", whatIt->first.toString().c_str(),
+ it->first.toString().c_str());
it = whatIt->second.erase(it);
} else {
++it;
@@ -338,7 +534,8 @@
if (verbose) {
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (const auto& slice : whatIt.second) {
- fprintf(out, "\t%s\t%s\n", whatIt.first.c_str(), slice.first.c_str());
+ fprintf(out, "\t(what)%s\t(condition)%s\n", whatIt.first.toString().c_str(),
+ slice.first.toString().c_str());
slice.second->dumpStates(out, verbose);
}
}
@@ -353,7 +550,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("DurationMetric %lld dropping data for dimension key %s",
- (long long)mMetricId, newKey.c_str());
+ (long long)mMetricId, newKey.toString().c_str());
return true;
}
}
@@ -388,14 +585,21 @@
return;
}
- std::vector<HashableDimensionKey> values;
- filterValues(mInternalDimensions, event.getValues(), &values);
- if (values.empty()) {
+ if (mInternalDimensions.empty()) {
it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
event.GetElapsedTimestampNs(), conditionKeys);
} else {
- for (const auto& value : values) {
- it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
+ if (mContainANYPositionInInternalDimensions) {
+ std::vector<HashableDimensionKey> dimensionKeys;
+ filterValues(mInternalDimensions, event.getValues(), &dimensionKeys);
+ for (const auto& key : dimensionKeys) {
+ it->second->noteStart(key, condition, event.GetElapsedTimestampNs(), conditionKeys);
+ }
+ } else {
+ HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
+ filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
+ it->second->noteStart(
+ dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
}
}
@@ -408,8 +612,113 @@
ALOGW("Not used in duration tracker.");
}
+void DurationMetricProducer::onMatchedLogEventLocked_simple(const size_t matcherIndex,
+ const LogEvent& event) {
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
+ if (eventTimeNs < mStartTimeNs) {
+ return;
+ }
+
+ flushIfNeededLocked(event.GetElapsedTimestampNs());
+
+ // Handles Stopall events.
+ if (matcherIndex == mStopAllIndex) {
+ for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
+ for (auto& pair : whatIt.second) {
+ pair.second->noteStopAll(event.GetElapsedTimestampNs());
+ }
+ }
+ return;
+ }
+
+ HashableDimensionKey dimensionInWhat;
+ if (!mDimensionsInWhat.empty()) {
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
+ } else {
+ dimensionInWhat = DEFAULT_DIMENSION_KEY;
+ }
+
+ // Handles Stop events.
+ if (matcherIndex == mStopIndex) {
+ if (mUseWhatDimensionAsInternalDimension) {
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ condIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
+ }
+ }
+ return;
+ }
+
+ HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
+ if (!mInternalDimensions.empty()) {
+ filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
+ }
+
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ condIt.second->noteStop(
+ internalDimensionKey, event.GetElapsedTimestampNs(), false);
+ }
+ }
+ return;
+ }
+
+ bool condition;
+ ConditionKey conditionKey;
+ std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
+ if (mConditionSliced) {
+ for (const auto& link : mMetric2ConditionLinks) {
+ getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
+ }
+
+ auto conditionState =
+ mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
+ &dimensionKeysInCondition);
+ condition = (conditionState == ConditionState::kTrue);
+ if (mDimensionsInCondition.empty() && condition) {
+ dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
+ }
+ } else {
+ condition = mCondition;
+ if (condition) {
+ dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
+ }
+ }
+
+ if (dimensionKeysInCondition.empty()) {
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
+ } else {
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
+ // If the what dimension is already there, we should update all the trackers even
+ // the condition is false.
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ const bool cond = dimensionKeysInCondition.find(condIt.first) !=
+ dimensionKeysInCondition.end();
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, condIt.first),
+ conditionKey, cond, event);
+ dimensionKeysInCondition.erase(condIt.first);
+ }
+ }
+ for (const auto& conditionDimension : dimensionKeysInCondition) {
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, conditionDimension), conditionKey,
+ condition, event);
+ }
+ }
+}
+
void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
const LogEvent& event) {
+ if (!mContainANYPositionInDimensionsInWhat) {
+ onMatchedLogEventLocked_simple(matcherIndex, event);
+ return;
+ }
+
uint64_t eventTimeNs = event.GetElapsedTimestampNs();
if (eventTimeNs < mStartTimeNs) {
return;
@@ -448,19 +757,17 @@
return;
}
- std::vector<HashableDimensionKey> internalDimensionKeys;
- filterValues(mInternalDimensions, event.getValues(), &internalDimensionKeys);
- if (internalDimensionKeys.empty()) {
- internalDimensionKeys.push_back(DEFAULT_DIMENSION_KEY);
+ HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
+ if (!mInternalDimensions.empty()) {
+ filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
}
+
for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
for (const auto& condIt : whatIt->second) {
- for (const auto& internalDimensionKey : internalDimensionKeys) {
- condIt.second->noteStop(
- internalDimensionKey, event.GetElapsedTimestampNs(), false);
- }
+ condIt.second->noteStop(
+ internalDimensionKey, event.GetElapsedTimestampNs(), false);
}
}
}
@@ -477,6 +784,8 @@
auto conditionState =
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
&dimensionKeysInCondition);
condition = (conditionState == ConditionState::kTrue);
if (mDimensionsInCondition.empty() && condition) {
@@ -490,32 +799,30 @@
}
for (const auto& whatDimension : dimensionInWhatValues) {
- auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
- // If the what dimension is already there, we should update all the trackers even
- // the condition is false.
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- const bool cond = dimensionKeysInCondition.find(condIt.first) !=
- dimensionKeysInCondition.end();
- handleStartEvent(MetricDimensionKey(whatDimension, condIt.first),
- conditionKey, cond, event);
- }
+ if (dimensionKeysInCondition.empty()) {
+ handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
} else {
- // If it is a new what dimension key, we need to handle the start events for all current
- // condition dimensions.
+ auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
+ // If the what dimension is already there, we should update all the trackers even
+ // the condition is false.
+ if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
+ for (const auto& condIt : whatIt->second) {
+ const bool cond = dimensionKeysInCondition.find(condIt.first) !=
+ dimensionKeysInCondition.end();
+ handleStartEvent(MetricDimensionKey(whatDimension, condIt.first),
+ conditionKey, cond, event);
+ dimensionKeysInCondition.erase(condIt.first);
+ }
+ }
for (const auto& conditionDimension : dimensionKeysInCondition) {
handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension),
conditionKey, condition, event);
}
}
- if (dimensionKeysInCondition.empty()) {
- handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
- }
}
}
-
size_t DurationMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 23408a7..6746e11 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -51,6 +51,9 @@
protected:
void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
+
+ void onMatchedLogEventLocked_simple(const size_t matcherIndex, const LogEvent& event);
+
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKeys, bool condition,
@@ -69,6 +72,9 @@
// Internal interface to handle sliced condition change.
void onSlicedConditionMayChangeLocked(const uint64_t eventTime) override;
+ void onSlicedConditionMayChangeLocked_opt1(const uint64_t eventTime);
+ void onSlicedConditionMayChangeLocked_opt2(const uint64_t eventTime);
+
// Internal function to calculate the current used bytes.
size_t byteSizeLocked() const override;
@@ -98,9 +104,14 @@
// The dimension from the atom predicate. e.g., uid, wakelock name.
vector<Matcher> mInternalDimensions;
+ bool mContainANYPositionInInternalDimensions;
+
// This boolean is true iff When mInternalDimensions == mDimensionsInWhat
bool mUseWhatDimensionAsInternalDimension;
+ // Caches the current unsliced part condition.
+ ConditionState mUnSlicedPartCondition;
+
// Save the past buckets and we can clear when the StatsLogReport is dumped.
// TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 288f563c..e479e5c 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -83,6 +83,7 @@
// TODO: use UidMap if uid->pkg_name is required
if (metric.has_dimensions_in_what()) {
translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
if (metric.has_dimensions_in_condition()) {
@@ -140,7 +141,7 @@
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
- VLOG(" dimension key %s", dimensionKey.c_str());
+ VLOG(" dimension key %s", dimensionKey.toString().c_str());
uint64_t wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
@@ -283,7 +284,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("GaugeMetric %lld dropping data for dimension key %s",
- (long long)mMetricId, newKey.c_str());
+ (long long)mMetricId, newKey.toString().c_str());
return true;
}
}
@@ -398,7 +399,8 @@
info.mGaugeAtoms = slice.second;
auto& bucketList = mPastBuckets[slice.first];
bucketList.push_back(info);
- VLOG("gauge metric %lld, dump key value: %s", (long long)mMetricId, slice.first.c_str());
+ VLOG("gauge metric %lld, dump key value: %s", (long long)mMetricId,
+ slice.first.toString().c_str());
}
// If we have anomaly trackers, we need to update the partial bucket values.
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 18694a1..6c90b03 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -39,9 +39,10 @@
for (const auto& link : mMetric2ConditionLinks) {
getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
}
-
auto conditionState =
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
&dimensionKeysInCondition);
condition = (conditionState == ConditionState::kTrue);
} else {
@@ -52,25 +53,41 @@
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
- vector<HashableDimensionKey> dimensionInWhatValues;
- if (!mDimensionsInWhat.empty()) {
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
- } else {
- dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
- }
+ if (mContainANYPositionInDimensionsInWhat) {
+ vector<HashableDimensionKey> dimensionInWhatValues;
+ if (!mDimensionsInWhat.empty()) {
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
+ } else {
+ dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
+ }
- for (const auto& whatDimension : dimensionInWhatValues) {
+ for (const auto& whatDimension : dimensionInWhatValues) {
+ for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
+ onMatchedLogEventInternalLocked(
+ matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey),
+ conditionKey, condition, event);
+ }
+ if (dimensionKeysInCondition.empty()) {
+ onMatchedLogEventInternalLocked(
+ matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
+ }
+ }
+ } else {
+ HashableDimensionKey dimensionInWhat;
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
+ MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
+ metricKey.setDimensionKeyInCondition(conditionDimensionKey);
onMatchedLogEventInternalLocked(
- matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey),
- conditionKey, condition, event);
+ matcherIndex, metricKey, conditionKey, condition, event);
}
if (dimensionKeysInCondition.empty()) {
onMatchedLogEventInternalLocked(
- matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
+ matcherIndex, metricKey, conditionKey, condition, event);
}
}
+
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 05b7f87..ea45f43 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -50,7 +50,11 @@
mCondition(conditionIndex >= 0 ? false : true),
mConditionSliced(false),
mWizard(wizard),
- mConditionTrackerIndex(conditionIndex){};
+ mConditionTrackerIndex(conditionIndex),
+ mContainANYPositionInDimensionsInWhat(false),
+ mSameConditionDimensionsInTracker(false),
+ mHasLinksToAllConditionDimensionsInTracker(false) {
+ }
virtual ~MetricProducer(){};
@@ -219,6 +223,16 @@
vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
vector<Matcher> mDimensionsInCondition; // The dimensions_in_condition defined in statsd_config
+ bool mContainANYPositionInDimensionsInWhat;
+
+ // True iff the condition dimensions equal to the sliced dimensions in the simple condition
+ // tracker. This field is always false for combinational condition trackers.
+ bool mSameConditionDimensionsInTracker;
+
+ // True iff the metric to condition links cover all dimension fields in the condition tracker.
+ // This field is always false for combinational condition trackers.
+ bool mHasLinksToAllConditionDimensionsInTracker;
+
std::vector<Metric2Condition> mMetric2ConditionLinks;
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index a32e037..dbab814 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -160,10 +160,18 @@
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricNoLink);
- FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricWithLink);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink);
- FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition);
+
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
+ FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition);
+
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index e88daf7..09913dc 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -80,6 +80,7 @@
mBucketSizeNs = bucketSizeMills * 1000000;
if (metric.has_dimensions_in_what()) {
translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
if (metric.has_dimensions_in_condition()) {
@@ -146,7 +147,7 @@
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
- VLOG(" dimension key %s", dimensionKey.c_str());
+ VLOG(" dimension key %s", dimensionKey.toString().c_str());
uint64_t wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
@@ -254,7 +255,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("ValueMetric %lld dropping data for dimension key %s",
- (long long)mMetricId, newKey.c_str());
+ (long long)mMetricId, newKey.toString().c_str());
return true;
}
}
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 8f236fa..7b3393f 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -64,7 +64,7 @@
sp<ConditionWizard> wizard, int conditionIndex,
const std::vector<Matcher>& dimensionInCondition, bool nesting,
uint64_t currentBucketStartNs, uint64_t currentBucketNum, uint64_t startTimeNs,
- uint64_t bucketSizeNs, bool conditionSliced,
+ uint64_t bucketSizeNs, bool conditionSliced, bool fullLink,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
: mConfigKey(key),
mTrackerId(id),
@@ -80,6 +80,7 @@
mCurrentBucketNum(currentBucketNum),
mStartTimeNs(startTimeNs),
mConditionSliced(conditionSliced),
+ mHasLinksToAllConditionDimensionsInTracker(fullLink),
mAnomalyTrackers(anomalyTrackers){};
virtual ~DurationTracker(){};
@@ -198,6 +199,9 @@
const bool mConditionSliced;
+ bool mSameConditionDimensionsInTracker;
+ bool mHasLinksToAllConditionDimensionsInTracker;
+
std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index b225560..8e0bf26 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -30,20 +30,33 @@
const vector<Matcher>& dimensionInCondition, bool nesting,
uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs,
- bool conditionSliced,
+ bool conditionSliced, bool fullLink,
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
: DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
- conditionSliced, anomalyTrackers) {
+ conditionSliced, fullLink, anomalyTrackers) {
+ if (mWizard != nullptr) {
+ mSameConditionDimensionsInTracker =
+ mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
+ }
}
unique_ptr<DurationTracker> MaxDurationTracker::clone(const uint64_t eventTime) {
auto clonedTracker = make_unique<MaxDurationTracker>(*this);
- for (auto it = clonedTracker->mInfos.begin(); it != clonedTracker->mInfos.end(); ++it) {
- it->second.lastStartTime = eventTime;
- it->second.lastDuration = 0;
+ for (auto it = clonedTracker->mInfos.begin(); it != clonedTracker->mInfos.end();) {
+ if (it->second.state != kStopped) {
+ it->second.lastStartTime = eventTime;
+ it->second.lastDuration = 0;
+ it++;
+ } else {
+ it = clonedTracker->mInfos.erase(it);
+ }
}
- return clonedTracker;
+ if (clonedTracker->mInfos.empty()) {
+ return nullptr;
+ } else {
+ return clonedTracker;
+ }
}
bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
@@ -59,7 +72,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("MaxDurTracker %lld dropping data for dimension key %s",
- (long long)mTrackerId, newKey.c_str());
+ (long long)mTrackerId, newKey.toString().c_str());
return true;
}
}
@@ -77,7 +90,7 @@
if (mConditionSliced) {
duration.conditionKeys = conditionKey;
}
- VLOG("MaxDuration: key %s start condition %d", key.c_str(), condition);
+ VLOG("MaxDuration: key %s start condition %d", key.toString().c_str(), condition);
switch (duration.state) {
case kStarted:
@@ -103,7 +116,7 @@
void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
bool forceStop) {
- VLOG("MaxDuration: key %s stop", key.c_str());
+ VLOG("MaxDuration: key %s stop", key.toString().c_str());
if (mInfos.find(key) == mInfos.end()) {
// we didn't see a start event before. do nothing.
return;
@@ -120,7 +133,7 @@
stopAnomalyAlarm();
duration.state = DurationState::kStopped;
int64_t durationTime = eventTime - duration.lastStartTime;
- VLOG("Max, key %s, Stop %lld %lld %lld", key.c_str(),
+ VLOG("Max, key %s, Stop %lld %lld %lld", key.toString().c_str(),
(long long)duration.lastStartTime, (long long)eventTime,
(long long)durationTime);
duration.lastDuration += durationTime;
@@ -241,13 +254,15 @@
std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
ConditionState conditionState = mWizard->query(
mConditionTrackerIndex, pair.second.conditionKeys, mDimensionInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
&conditionDimensionKeySet);
bool conditionMet =
(conditionState == ConditionState::kTrue) &&
(mDimensionInCondition.size() == 0 ||
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
conditionDimensionKeySet.end());
- VLOG("key: %s, condition: %d", pair.first.c_str(), conditionMet);
+ VLOG("key: %s, condition: %d", pair.first.toString().c_str(), conditionMet);
noteConditionChanged(pair.first, conditionMet, timestamp);
}
}
@@ -277,7 +292,7 @@
// In case any other dimensions are still started, we need to set the alarm.
startAnomalyAlarm(timestamp);
}
- VLOG("MaxDurationTracker Key: %s Started->Paused ", key.c_str());
+ VLOG("MaxDurationTracker Key: %s Started->Paused ", key.toString().c_str());
}
break;
case kStopped:
@@ -290,7 +305,7 @@
it->second.state = DurationState::kStarted;
it->second.lastStartTime = timestamp;
startAnomalyAlarm(timestamp);
- VLOG("MaxDurationTracker Key: %s Paused->Started", key.c_str());
+ VLOG("MaxDurationTracker Key: %s Paused->Started", key.toString().c_str());
}
break;
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index c731b75..0452d37 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -33,6 +33,7 @@
const std::vector<Matcher>& dimensionInCondition, bool nesting,
uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
+ bool fullLink,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
MaxDurationTracker(const MaxDurationTracker& tracker) = default;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index f583f91..2358415 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -28,14 +28,18 @@
const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, const vector<Matcher>& dimensionInCondition,
bool nesting, uint64_t currentBucketStartNs, uint64_t currentBucketNum,
- uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
+ uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced, bool fullLink,
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
: DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
- conditionSliced, anomalyTrackers),
+ conditionSliced, fullLink, anomalyTrackers),
mStarted(),
mPaused() {
mLastStartTime = 0;
+ if (mWizard != nullptr) {
+ mSameConditionDimensionsInTracker =
+ mWizard->equalOutputDimensions(conditionIndex, mDimensionInCondition);
+ }
}
unique_ptr<DurationTracker> OringDurationTracker::clone(const uint64_t eventTime) {
@@ -57,7 +61,7 @@
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("OringDurTracker %lld dropping data for dimension key %s",
- (long long)mTrackerId, newKey.c_str());
+ (long long)mTrackerId, newKey.toString().c_str());
return true;
}
}
@@ -83,13 +87,13 @@
if (mConditionSliced && mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
mConditionKeyMap[key] = conditionKey;
}
- VLOG("Oring: %s start, condition %d", key.c_str(), condition);
+ VLOG("Oring: %s start, condition %d", key.toString().c_str(), condition);
}
void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp,
const bool stopAll) {
declareAnomalyIfAlarmExpired(timestamp);
- VLOG("Oring: %s stop", key.c_str());
+ VLOG("Oring: %s stop", key.toString().c_str());
auto it = mStarted.find(key);
if (it != mStarted.end()) {
(it->second)--;
@@ -217,22 +221,26 @@
if (!mStarted.empty()) {
for (auto it = mStarted.begin(); it != mStarted.end();) {
const auto& key = it->first;
- if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
- VLOG("Key %s dont have condition key", key.c_str());
+ const auto& condIt = mConditionKeyMap.find(key);
+ if (condIt == mConditionKeyMap.end()) {
+ VLOG("Key %s dont have condition key", key.toString().c_str());
++it;
continue;
}
std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
ConditionState conditionState =
- mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
- mDimensionInCondition, &conditionDimensionKeySet);
+ mWizard->query(mConditionTrackerIndex, condIt->second,
+ mDimensionInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
+ &conditionDimensionKeySet);
if (conditionState != ConditionState::kTrue ||
(mDimensionInCondition.size() != 0 &&
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) ==
conditionDimensionKeySet.end())) {
startedToPaused.push_back(*it);
it = mStarted.erase(it);
- VLOG("Key %s started -> paused", key.c_str());
+ VLOG("Key %s started -> paused", key.toString().c_str());
} else {
++it;
}
@@ -250,21 +258,24 @@
for (auto it = mPaused.begin(); it != mPaused.end();) {
const auto& key = it->first;
if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
- VLOG("Key %s dont have condition key", key.c_str());
+ VLOG("Key %s dont have condition key", key.toString().c_str());
++it;
continue;
}
std::unordered_set<HashableDimensionKey> conditionDimensionKeySet;
ConditionState conditionState =
mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
- mDimensionInCondition, &conditionDimensionKeySet);
+ mDimensionInCondition,
+ !mSameConditionDimensionsInTracker,
+ !mHasLinksToAllConditionDimensionsInTracker,
+ &conditionDimensionKeySet);
if (conditionState == ConditionState::kTrue &&
(mDimensionInCondition.size() == 0 ||
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
conditionDimensionKeySet.end())) {
pausedToStarted.push_back(*it);
it = mPaused.erase(it);
- VLOG("Key %s paused -> started", key.c_str());
+ VLOG("Key %s paused -> started", key.toString().c_str());
} else {
++it;
}
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 07c1329..610e3ea 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -32,6 +32,7 @@
int conditionIndex, const std::vector<Matcher>& dimensionInCondition,
bool nesting, uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
+ bool fullLink,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
OringDurationTracker(const OringDurationTracker& tracker) = default;
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index bbaf50a..80e46d6 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -32,7 +32,7 @@
// Minimum bucket size in seconds
const long kMinBucketSizeSec = 5 * 60;
-typedef std::map<int64_t, std::vector<HashableDimensionKey>> ConditionKey;
+typedef std::map<int64_t, HashableDimensionKey> ConditionKey;
typedef std::unordered_map<MetricDimensionKey, int64_t> DimToValMap;
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1e8aa12..1c99e2a 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -295,6 +295,7 @@
message BroadcastSubscriberDetails {
optional int64 subscriber_id = 1;
+ repeated string cookie = 2;
}
message Subscription {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 95ecf80..25d2257 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -77,6 +77,12 @@
}
int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
+ vector<String16> cookies;
+ cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
+ for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
+ cookies.push_back(String16(cookie.c_str()));
+ }
+
auto it1 = mIntentMap.find(configKey);
if (it1 == mIntentMap.end()) {
ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str());
@@ -88,12 +94,13 @@
configKey.ToString().c_str(), (long long)subscriberId);
return;
}
- sendBroadcastLocked(it2->second, configKey, subscription, dimKey);
+ sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
}
void SubscriberReporter::sendBroadcastLocked(const sp<IBinder>& intentSender,
const ConfigKey& configKey,
const Subscription& subscription,
+ const vector<String16>& cookies,
const MetricDimensionKey& dimKey) const {
VLOG("SubscriberReporter::sendBroadcastLocked called.");
if (mStatsCompanionService == nullptr) {
@@ -101,11 +108,16 @@
return;
}
mStatsCompanionService->sendSubscriberBroadcast(
- intentSender, configKey.GetUid(), configKey.GetId(), subscription.id(),
- subscription.rule_id(), getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
+ intentSender,
+ configKey.GetUid(),
+ configKey.GetId(),
+ subscription.id(),
+ subscription.rule_id(),
+ cookies,
+ getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
}
-void getStatsDimensionsValueHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
+void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth,
int prefix, vector<StatsDimensionsValue>* output) {
size_t count = dims.size();
while (*index < count) {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 50100df..2a7f771 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -26,6 +26,7 @@
#include <mutex>
#include <unordered_map>
+#include <vector>
namespace android {
namespace os {
@@ -102,6 +103,7 @@
void sendBroadcastLocked(const sp<android::IBinder>& intentSender,
const ConfigKey& configKey,
const Subscription& subscription,
+ const std::vector<String16>& cookies,
const MetricDimensionKey& dimKey) const;
};
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 3dc3fd1..e826a52 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -75,10 +75,10 @@
event->init();
}
-std::map<int64_t, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
+std::map<int64_t, HashableDimensionKey> getWakeLockQueryKey(
const Position position,
const std::vector<int> &uids, const string& conditionName) {
- std::map<int64_t, std::vector<HashableDimensionKey>> outputKeyMap;
+ std::map<int64_t, HashableDimensionKey> outputKeyMap;
std::vector<int> uid_indexes;
int pos[] = {1, 1, 1};
int depth = 2;
@@ -104,7 +104,7 @@
Value value((int32_t)uids[idx]);
HashableDimensionKey dim;
dim.addValue(FieldValue(field, value));
- outputKeyMap[StringToId(conditionName)].push_back(dim);
+ outputKeyMap[StringToId(conditionName)] = dim;
}
return outputKeyMap;
}
@@ -122,6 +122,7 @@
SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/,
simplePredicate, trackerNameIndexMap);
+ EXPECT_FALSE(conditionTracker.isSliced());
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -193,6 +194,7 @@
}
TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
+ std::vector<sp<ConditionTracker>> allConditions;
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
@@ -205,6 +207,7 @@
SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
+ EXPECT_FALSE(conditionTracker.isSliced());
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -257,14 +260,14 @@
conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
- // result should still be true
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
EXPECT_TRUE(changedCache[0]);
}
TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
+ std::vector<sp<ConditionTracker>> allConditions;
for (Position position :
- { Position::ANY, Position::FIRST, Position::LAST}) {
+ { Position::FIRST, Position::LAST}) {
vector<Matcher> dimensionInCondition;
std::unordered_set<HashableDimensionKey> dimensionKeys;
@@ -281,6 +284,7 @@
SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
+
std::vector<int> uids = {111, 222, 333};
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -305,12 +309,20 @@
EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
+ if (position == Position::FIRST ||
+ position == Position::LAST) {
+ EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u);
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), uids.size());
+ }
// Now test query
const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ false, false,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -331,6 +343,9 @@
} else {
EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+
// wake lock 1 release
LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
@@ -350,6 +365,8 @@
} else {
EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
}
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
makeWakeLockEvent(&event4, uids, "wl2", 0); // now release it.
@@ -362,18 +379,26 @@
changedCache);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
+ if (position == Position::FIRST ||
+ position == Position::LAST) {
+ EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u);
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), uids.size());
+ }
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ false, false,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-
}
}
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
+ std::vector<sp<ConditionTracker>> allConditions;
vector<Matcher> dimensionInCondition;
std::unordered_set<HashableDimensionKey> dimensionKeys;
@@ -391,6 +416,8 @@
0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
+ EXPECT_FALSE(conditionTracker.isSliced());
+
std::vector<int> uid_list1 = {111, 1111, 11111};
string uid1_wl1 = "wl1_1";
std::vector<int> uid_list2 = {222, 2222, 22222};
@@ -419,6 +446,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ true, true,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -463,13 +491,15 @@
conditionCache[0] = ConditionState::kNotEvaluated;
dimensionKeys.clear();
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ true, true,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
TEST(SimpleConditionTrackerTest, TestStopAll) {
+ std::vector<sp<ConditionTracker>> allConditions;
for (Position position :
- {Position::ANY, Position::FIRST, Position::LAST}) {
+ { Position::FIRST, Position::LAST }) {
vector<Matcher> dimensionInCondition;
std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
@@ -510,12 +540,23 @@
EXPECT_EQ(uid_list1.size(), conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
+ {
+ if (position == Position::FIRST ||
+ position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uid_list1.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ }
+ }
// Now test query
const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ false, false,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -538,11 +579,23 @@
conditionTracker.mSlicedConditionState.size());
}
EXPECT_TRUE(changedCache[0]);
+ {
+ if (position == Position::FIRST ||
+ position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uid_list2.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ }
+ }
+
// TEST QUERY
const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ false, false,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -561,11 +614,22 @@
changedCache);
EXPECT_TRUE(changedCache[0]);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uid_list1.size() + uid_list2.size(),
+ conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ }
+ }
// TEST QUERY
const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ false, false,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
@@ -573,6 +637,7 @@
const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
conditionTracker.isConditionMet(queryKey, allPredicates, dimensionInCondition,
+ false, false,
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
new file mode 100644
index 0000000..a08f606
--- /dev/null
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -0,0 +1,879 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
+ DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
+ {Position::FIRST});
+ if (addExtraDimensionInCondition) {
+ syncDimension->add_child()->set_field(2 /* name field*/);
+ }
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = screenIsOffPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+ auto combinationPredicate = config.add_predicate();
+ combinationPredicate->set_id(StringToId("CombinationPredicate"));
+ combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
+ addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
+ auto dimensionWhat = metric->mutable_dimensions_in_what();
+ dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(2); // job name field.
+ *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+} // namespace
+
+TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {
+ for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
+ for (auto aggregationType : {DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
+ ConfigKey cfgKey;
+ auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
+ aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 11));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 40));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 102));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 450));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 650));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 100));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + bucketSizeNs + 640));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 650));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 10));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 200));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 300));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 401));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ StatsLogReport::DurationMetricDataWrapper metrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).duration_metrics(), &metrics);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job0"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+
+ data = metrics.data(1);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job1"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100 + 650 - 640);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job0"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job1"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 110);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
+ }
+ }
+}
+
+namespace {
+
+StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
+ DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *dimensions = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ if (addExtraDimensionInCondition) {
+ syncDimension->add_child()->set_field(2 /* name field*/);
+ }
+
+ auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = screenIsOffPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+ auto combinationPredicate = config.add_predicate();
+ combinationPredicate->set_id(StringToId("CombinationPredicate"));
+ combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
+ addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
+ *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+
+ auto links = metric->add_links();
+ links->set_condition(isSyncingPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+} // namespace
+
+TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition) {
+ for (bool isFullLink : {true, false}) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ ConfigKey cfgKey;
+ auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
+ aggregationType, !isFullLink);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions3 = {
+ CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 55));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 120));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 121));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 450));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 501));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 100));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",
+ bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(
+ CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs - 2));
+ events.push_back(
+ CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 110));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 300));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 550));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 800));
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ StatsLogReport::DurationMetricDataWrapper metrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).duration_metrics(), &metrics);
+
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(metrics.data_size(), 3);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(metrics.data_size(), 3);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
+ }
+ }
+}
+
+namespace {
+
+StatsdConfig CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
+ DurationMetric::AggregationType aggregationType) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *dimensions = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ syncDimension->add_child()->set_field(2 /* name field*/);
+
+ auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = screenIsOffPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+ auto combinationPredicate = config.add_predicate();
+ combinationPredicate->set_id(StringToId("CombinationPredicate"));
+ combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
+ addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
+ *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *metric->mutable_dimensions_in_condition() = *syncDimension;
+
+
+ auto links = metric->add_links();
+ links->set_condition(isSyncingPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+} // namespace
+
+TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ ConfigKey cfgKey;
+ auto config =
+ CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(aggregationType);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions3 = {
+ CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 55));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 120));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 121));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 450));
+
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 501));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 100));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",
+ bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(
+ CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs - 2));
+ events.push_back(
+ CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 110));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 300));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 550));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 800));
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ StatsLogReport::DurationMetricDataWrapper metrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).duration_metrics(), &metrics);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 600 + 50);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 50);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
+ }
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
similarity index 85%
rename from cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
rename to cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index 01348bd..435e199 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -28,7 +28,7 @@
namespace {
-StatsdConfig CreateCountMetricWithNoLinkConfig() {
+StatsdConfig CreateCountMetric_NoLink_CombinationCondition_Config() {
StatsdConfig config;
auto screenBrightnessChangeAtomMatcher = CreateScreenBrightnessChangedAtomMatcher();
*config.add_atom_matcher() = screenBrightnessChangeAtomMatcher;
@@ -67,9 +67,9 @@
} // namespace
-TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
+TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition) {
ConfigKey cfgKey;
- auto config = CreateCountMetricWithNoLinkConfig();
+ auto config = CreateCountMetric_NoLink_CombinationCondition_Config();
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
@@ -227,7 +227,7 @@
namespace {
-StatsdConfig CreateCountMetricWithLinkConfig() {
+StatsdConfig CreateCountMetric_Link_CombinationCondition() {
StatsdConfig config;
auto appCrashMatcher = CreateProcessCrashAtomMatcher();
*config.add_atom_matcher() = appCrashMatcher;
@@ -274,9 +274,9 @@
} // namespace
-TEST(DimensionInConditionE2eTest, TestCountMetricWithLink) {
+TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition) {
ConfigKey cfgKey;
- auto config = CreateCountMetricWithLinkConfig();
+ auto config = CreateCountMetric_Link_CombinationCondition();
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
@@ -413,7 +413,8 @@
namespace {
-StatsdConfig CreateDurationMetricConfigNoLink(DurationMetric::AggregationType aggregationType) {
+StatsdConfig CreateDurationMetricConfig_NoLink_CombinationCondition(
+ DurationMetric::AggregationType aggregationType) {
StatsdConfig config;
*config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
*config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
@@ -445,6 +446,7 @@
metric->set_id(StringToId("BatterySaverModeDurationMetric"));
metric->set_what(inBatterySaverModePredicate.id());
metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
return config;
@@ -452,10 +454,10 @@
} // namespace
-TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink) {
- for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition) {
+ for (auto aggregationType : { DurationMetric::MAX_SPARSE}) { // DurationMetric::SUM,
ConfigKey cfgKey;
- auto config = CreateDurationMetricConfigNoLink(aggregationType);
+ auto config = CreateDurationMetricConfig_NoLink_CombinationCondition(aggregationType);
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
@@ -529,43 +531,77 @@
auto data = metrics.data(0);
EXPECT_FALSE(data.dimensions_in_what().has_field());
EXPECT_FALSE(data.dimensions_in_condition().has_field());
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
data = metrics.data(1);
EXPECT_FALSE(data.dimensions_in_what().has_field());
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
+
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
+ } else {
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 300);
+ }
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(2);
EXPECT_FALSE(data.dimensions_in_what().has_field());
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ } else {
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs + 700 - 600);
+ }
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
}
}
namespace {
-StatsdConfig CreateDurationMetricConfigWithLink(DurationMetric::AggregationType aggregationType) {
+StatsdConfig CreateDurationMetricConfig_Link_CombinationCondition(
+ DurationMetric::AggregationType aggregationType) {
StatsdConfig config;
*config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
*config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
@@ -599,6 +635,7 @@
metric->set_id(StringToId("AppInBackgroundMetric"));
metric->set_what(isInBackgroundPredicate.id());
metric->set_condition(combinationPredicate->id());
+ metric->set_aggregation_type(aggregationType);
*metric->mutable_dimensions_in_what() =
CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
@@ -617,10 +654,10 @@
} // namespace
-TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink) {
+TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationCondition) {
for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
ConfigKey cfgKey;
- auto config = CreateDurationMetricConfigWithLink(aggregationType);
+ auto config = CreateDurationMetricConfig_Link_CombinationCondition(aggregationType);
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
@@ -701,26 +738,50 @@
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
android::util::SYNC_STATE_CHANGED, 111, "App1");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 100 - 201);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
data = metrics.data(2);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
android::util::SYNC_STATE_CHANGED, 333, "App2");
- EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
- EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs + 299);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
}
}
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
new file mode 100644
index 0000000..75ceafb
--- /dev/null
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -0,0 +1,799 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition(
+ DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
+ {Position::FIRST});
+ if (addExtraDimensionInCondition) {
+ syncDimension->add_child()->set_field(2 /* name field*/);
+ }
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(isSyncingPredicate.id());
+ metric->set_aggregation_type(aggregationType);
+ auto dimensionWhat = metric->mutable_dimensions_in_what();
+ dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(2); // job name field.
+ *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+} // namespace
+
+TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) {
+ for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : {true, false}) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ ConfigKey cfgKey;
+ auto config = CreateDurationMetricConfig_NoLink_SimpleCondition(
+ aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 1));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 10));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 200));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 300));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 401));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ StatsLogReport::DurationMetricDataWrapper metrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).duration_metrics(), &metrics);
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job0"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job1"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job0"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job1"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 300);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ EXPECT_EQ(data.dimensions_in_what().field(),
+ android::util::SCHEDULED_JOB_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
+ 2); // job name field
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
+ "job2"); // job name
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 );
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
+ }
+ }
+}
+
+namespace {
+
+StatsdConfig createDurationMetric_Link_SimpleConditionConfig(
+ DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *dimensions = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ if (addExtraDimensionInCondition) {
+ syncDimension->add_child()->set_field(2 /* name field*/);
+ }
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(isSyncingPredicate.id());
+ metric->set_aggregation_type(aggregationType);
+ *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+
+ auto links = metric->add_links();
+ links->set_condition(isSyncingPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+} // namespace
+
+TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) {
+ for (bool isFullLink : {true, false}) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ ConfigKey cfgKey;
+ auto config = createDurationMetric_Link_SimpleConditionConfig(
+ aggregationType, !isFullLink);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions3 = {
+ CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(
+ CreateFinishScheduledJobEvent({CreateAttribution(333, "App2")}, "job2",
+ bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(
+ CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs - 2));
+ events.push_back(
+ CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 110));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 300));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 550));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 800));
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ StatsLogReport::DurationMetricDataWrapper metrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).duration_metrics(), &metrics);
+
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(metrics.data_size(), 3);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(metrics.data_size(), 3);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
+ }
+ }
+}
+
+namespace {
+
+StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig(
+ DurationMetric::AggregationType aggregationType) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
+
+ auto scheduledJobPredicate = CreateScheduledJobPredicate();
+ auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *dimensions = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ dimensions->add_child()->set_field(2); // job name field.
+
+ auto isSyncingPredicate = CreateIsSyncingPredicate();
+ auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
+ *syncDimension = CreateAttributionUidDimensions(
+ android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ syncDimension->add_child()->set_field(2 /* name field*/);
+
+ *config.add_predicate() = scheduledJobPredicate;
+ *config.add_predicate() = isSyncingPredicate;
+
+ auto metric = config.add_duration_metric();
+ metric->set_bucket(FIVE_MINUTES);
+ metric->set_id(StringToId("scheduledJob"));
+ metric->set_what(scheduledJobPredicate.id());
+ metric->set_condition(isSyncingPredicate.id());
+ metric->set_aggregation_type(aggregationType);
+ *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *metric->mutable_dimensions_in_condition() = *syncDimension;
+
+ auto links = metric->add_links();
+ links->set_condition(isSyncingPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(
+ android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ return config;
+}
+
+} // namespace
+
+TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ ConfigKey cfgKey;
+ auto config = createDurationMetric_PartialLink_SimpleConditionConfig(
+ aggregationType);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto processor = CreateStatsLogProcessor(
+ bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<AttributionNodeInternal> attributions1 = {
+ CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions2 = {
+ CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<AttributionNodeInternal> attributions3 = {
+ CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
+ events.push_back(CreateStartScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
+ events.push_back(CreateFinishScheduledJobEvent(
+ {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850));
+
+ events.push_back(
+ CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs - 2));
+ events.push_back(
+ CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
+ bucketStartTimeNs + bucketSizeNs + 900));
+
+ events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 50));
+ events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
+ bucketStartTimeNs + 110));
+
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + 300));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
+ bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + 400));
+ events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 550));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + 800));
+ events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
+ bucketStartTimeNs + bucketSizeNs + 700));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ StatsLogReport::DurationMetricDataWrapper metrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).duration_metrics(), &metrics);
+
+ if (aggregationType == DurationMetric::SUM) {
+ EXPECT_EQ(4, metrics.data_size());
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 400 - 100);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ } else {
+ EXPECT_EQ(metrics.data_size(), 4);
+ auto data = metrics.data(0);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+
+ data = metrics.data(1);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
+
+ data = metrics.data(2);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
+ EXPECT_EQ("ReadEmail",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = metrics.data(3);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
+ ValidateAttributionUidDimension(
+ data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
+ EXPECT_EQ("ReadDoc",
+ data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ }
+ }
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
index 7d9c8a8..fc6e420 100644
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -34,7 +34,7 @@
* Test merge isolated and host uid
*/
-int uidAtomTagId = android::util::CPU_TIME_PER_UID_FREQ;
+int uidAtomTagId = android::util::CPU_CLUSTER_TIME;
int nonUidAtomTagId = android::util::SYSTEM_UPTIME;
int timestamp = 1234;
int isolatedUid = 30;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 9a0de0d..a07683e 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -175,9 +175,9 @@
{getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*wizard, query(_, key1, _, _)).WillOnce(Return(ConditionState::kFalse));
+ EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
- EXPECT_CALL(*wizard, query(_, key2, _, _)).WillOnce(Return(ConditionState::kTrue));
+ EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
bucketStartTimeNs);
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 8246268..23d3171 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -113,9 +113,9 @@
key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*wizard, query(_, key1, _, _)).WillOnce(Return(ConditionState::kFalse));
+ EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
- EXPECT_CALL(*wizard, query(_, key2, _, _)).WillOnce(Return(ConditionState::kTrue));
+ EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 83b1cbf..57a8925 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -42,14 +42,13 @@
const int TagId = 1;
const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "1");
-const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
+const HashableDimensionKey conditionKey = getMockedDimensionKey(TagId, 4, "1");
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
const uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
@@ -66,7 +65,7 @@
int64_t metricId = 1;
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- false, {});
+ false, false, {});
tracker.noteStart(key1, true, bucketStartTimeNs, ConditionKey());
// Event starts again. This would not change anything as it already starts.
@@ -86,7 +85,6 @@
TEST(MaxDurationTrackerTest, TestStopAll) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
@@ -103,7 +101,7 @@
int64_t metricId = 1;
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- false, {});
+ false, false, {});
tracker.noteStart(key1, true, bucketStartTimeNs + 1, ConditionKey());
@@ -124,7 +122,6 @@
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
vector<Matcher> dimensionInCondition;
@@ -140,7 +137,7 @@
int64_t metricId = 1;
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- false, {});
+ false, false, {});
// The event starts.
tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, ConditionKey());
@@ -166,7 +163,6 @@
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
vector<Matcher> dimensionInCondition;
@@ -182,7 +178,7 @@
int64_t metricId = 1;
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- false, {});
+ false, false, {});
// 2 starts
tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, ConditionKey());
@@ -204,14 +200,14 @@
}
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
- const std::vector<HashableDimensionKey> conditionKey = {key1};
+ const HashableDimensionKey conditionDimKey = key1;
vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 1, "1");
- conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
+ conditionKey1[StringToId("APP_BACKGROUND")] = conditionDimKey;
/**
Start in first bucket, stop in second bucket. Condition turns on and off in the first bucket
@@ -229,7 +225,7 @@
int64_t metricId = 1;
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, 0, bucketStartTimeNs, bucketSizeNs, true,
- {});
+ false, {});
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
tracker.noteStart(key1, false, eventStartTimeNs, conditionKey1);
@@ -250,8 +246,6 @@
}
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
-
vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -281,7 +275,7 @@
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- true, {anomalyTracker});
+ true, false, {anomalyTracker});
tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
@@ -301,8 +295,6 @@
// This tests that we correctly compute the predicted time of an anomaly assuming that the current
// state continues forward as-is.
TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
-
vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -310,7 +302,7 @@
MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 2, "maps");
conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
ConditionKey conditionKey2;
- conditionKey2[StringToId("APP_BACKGROUND")] = {getMockedDimensionKey(TagId, 4, "2")};
+ conditionKey2[StringToId("APP_BACKGROUND")] = getMockedDimensionKey(TagId, 4, "2");
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -343,7 +335,7 @@
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- true, {anomalyTracker});
+ true, false, {anomalyTracker});
tracker.noteStart(key1, false, eventStartTimeNs, conditionKey1);
tracker.noteConditionChanged(key1, true, conditionStarts1);
@@ -360,8 +352,6 @@
// Suppose A starts, then B starts, and then A stops. We still need to set an anomaly based on the
// elapsed duration of B.
TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
- const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
-
vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -369,7 +359,7 @@
MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 2, "maps");
conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
ConditionKey conditionKey2;
- conditionKey2[StringToId("APP_BACKGROUND")] = {getMockedDimensionKey(TagId, 4, "2")};
+ conditionKey2[StringToId("APP_BACKGROUND")] = getMockedDimensionKey(TagId, 4, "2");
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -399,7 +389,7 @@
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
- true, {anomalyTracker});
+ true, false, {anomalyTracker});
tracker.noteStart(key1, true, eventStartTimeNs1, conditionKey1);
tracker.noteStart(key2, true, eventStartTimeNs2, conditionKey2);
@@ -415,4 +405,4 @@
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+#endif
\ No newline at end of file
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index aa41038..54abcb2 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -40,7 +40,7 @@
const int64_t metricId = 123;
const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
-const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
+const HashableDimensionKey kConditionKey1 = getMockedDimensionKey(TagId, 1, "maps");
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
const uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
@@ -48,8 +48,6 @@
TEST(OringDurationTrackerTest, TestDurationOverlap) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -65,7 +63,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, false, {});
+ bucketSizeNs, false, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -83,8 +81,6 @@
TEST(OringDurationTrackerTest, TestDurationNested) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -99,7 +95,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, false, {});
+ bucketSizeNs, false, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, ConditionKey()); // overlapping wl
@@ -132,7 +128,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, false, {});
+ bucketSizeNs, false, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, ConditionKey()); // overlapping wl
@@ -148,8 +144,6 @@
TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -165,7 +159,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, false, {});
+ bucketSizeNs, false, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -189,8 +183,6 @@
TEST(OringDurationTrackerTest, TestDurationConditionChange) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -199,7 +191,7 @@
ConditionKey key1;
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
- EXPECT_CALL(*wizard, query(_, key1, _, _)) // #4
+ EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)) // #4
.WillOnce(Return(ConditionState::kFalse));
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -212,7 +204,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, true, {});
+ bucketSizeNs, true, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -229,8 +221,6 @@
TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -239,7 +229,7 @@
ConditionKey key1;
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
- EXPECT_CALL(*wizard, query(_, key1, _, _))
+ EXPECT_CALL(*wizard, query(_, key1, _, _, _, _))
.Times(2)
.WillOnce(Return(ConditionState::kFalse))
.WillOnce(Return(ConditionState::kTrue));
@@ -254,7 +244,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, true, {});
+ bucketSizeNs, true, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
// condition to false; record duration 5n
@@ -273,8 +263,6 @@
TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -283,7 +271,7 @@
ConditionKey key1;
key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
- EXPECT_CALL(*wizard, query(_, key1, _, _)) // #4
+ EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)) // #4
.WillOnce(Return(ConditionState::kFalse));
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -295,7 +283,7 @@
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, true, {});
+ bucketSizeNs, true, false, {});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
@@ -315,8 +303,6 @@
TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -339,7 +325,7 @@
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, true, {anomalyTracker});
+ bucketSizeNs, true, false, {anomalyTracker});
// Nothing in the past bucket.
tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
@@ -386,7 +372,6 @@
TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -410,7 +395,7 @@
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
- bucketSizeNs, false, {anomalyTracker});
+ bucketSizeNs, false, false, {anomalyTracker});
tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
tracker.noteStop(kEventKey1, eventStartTimeNs + 10, false);
@@ -437,8 +422,6 @@
TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
- const std::vector<HashableDimensionKey> kConditionKey1 =
- {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
vector<Matcher> dimensionInCondition;
@@ -462,7 +445,7 @@
new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs,
- bucketSizeNs, false, {anomalyTracker});
+ bucketSizeNs, false, false, {anomalyTracker});
tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
@@ -508,4 +491,4 @@
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
+#endif
\ No newline at end of file
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index a01de63..f040bf9 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -26,9 +26,10 @@
class MockConditionWizard : public ConditionWizard {
public:
- MOCK_METHOD4(query,
+ MOCK_METHOD6(query,
ConditionState(const int conditionIndex, const ConditionKey& conditionParameters,
const vector<Matcher>& dimensionFields,
+ const bool isSubsetDim, const bool isPartialLink,
std::unordered_set<HashableDimensionKey>* dimensionKeySet));
};
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 242b6eb..2678c8a 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -26,6 +26,28 @@
return atom_matcher;
}
+AtomMatcher CreateScheduledJobStateChangedAtomMatcher(const string& name,
+ ScheduledJobStateChanged::State state) {
+ AtomMatcher atom_matcher;
+ atom_matcher.set_id(StringToId(name));
+ auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
+ simple_atom_matcher->set_atom_id(android::util::SCHEDULED_JOB_STATE_CHANGED);
+ auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
+ field_value_matcher->set_field(3); // State field.
+ field_value_matcher->set_eq_int(state);
+ return atom_matcher;
+}
+
+AtomMatcher CreateStartScheduledJobAtomMatcher() {
+ return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobStart",
+ ScheduledJobStateChanged::STARTED);
+}
+
+AtomMatcher CreateFinishScheduledJobAtomMatcher() {
+ return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobFinish",
+ ScheduledJobStateChanged::FINISHED);
+}
+
AtomMatcher CreateScreenBrightnessChangedAtomMatcher() {
AtomMatcher atom_matcher;
atom_matcher.set_id(StringToId("ScreenBrightnessChanged"));
@@ -168,6 +190,14 @@
"ProcessCrashed", ProcessLifeCycleStateChanged::PROCESS_CRASHED);
}
+Predicate CreateScheduledJobPredicate() {
+ Predicate predicate;
+ predicate.set_id(StringToId("ScheduledJobRunningPredicate"));
+ predicate.mutable_simple_predicate()->set_start(StringToId("ScheduledJobStart"));
+ predicate.mutable_simple_predicate()->set_stop(StringToId("ScheduledJobFinish"));
+ return predicate;
+}
+
Predicate CreateBatterySaverModePredicate() {
Predicate predicate;
predicate.set_id(StringToId("BatterySaverIsOn"));
@@ -290,6 +320,32 @@
}
+std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
+ const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
+ const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
+ event->write(attributions);
+ event->write(jobName);
+ event->write(state);
+ event->init();
+ return event;
+}
+
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs) {
+ return CreateScheduledJobStateChangedEvent(
+ attributions, name, ScheduledJobStateChanged::STARTED, timestampNs);
+}
+
+// Create log event when scheduled job finishes.
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs) {
+ return CreateScheduledJobStateChangedEvent(
+ attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs);
+}
+
std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(
const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
const WakelockStateChanged::State state, uint64_t timestampNs) {
@@ -419,7 +475,6 @@
void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1);
// Attribution field.
EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
// Uid only.
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 1708cc3..14eba1f 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -28,6 +28,15 @@
// Create AtomMatcher proto to simply match a specific atom type.
AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
+// Create AtomMatcher proto for scheduled job state changed.
+AtomMatcher CreateScheduledJobStateChangedAtomMatcher();
+
+// Create AtomMatcher proto for starting a scheduled job.
+AtomMatcher CreateStartScheduledJobAtomMatcher();
+
+// Create AtomMatcher proto for a scheduled job is done.
+AtomMatcher CreateFinishScheduledJobAtomMatcher();
+
// Create AtomMatcher proto for screen brightness state changed.
AtomMatcher CreateScreenBrightnessChangedAtomMatcher();
@@ -73,6 +82,9 @@
// Create Predicate proto for screen is off.
Predicate CreateScreenIsOffPredicate();
+// Create Predicate proto for a running scheduled job.
+Predicate CreateScheduledJobPredicate();
+
// Create Predicate proto for battery saver mode.
Predicate CreateBatterySaverModePredicate();
@@ -107,6 +119,16 @@
std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
int level, uint64_t timestampNs);
+// Create log event when scheduled job starts.
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs);
+
+// Create log event when scheduled job finishes.
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
+ const std::vector<AttributionNodeInternal>& attributions,
+ const string& name, uint64_t timestampNs);
+
// Create log event when battery saver starts.
std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs);
// Create log event when battery saver stops.
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9528ff1..771d860 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -3,19 +3,12 @@
Landroid/accounts/IAccountManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/animation/LayoutTransition;->cancel()V
Landroid/animation/ValueAnimator;->animateValue(F)V
-Landroid/animation/ValueAnimator;->getDurationScale()F
Landroid/animation/ValueAnimator;->sDurationScale:F
-Landroid/animation/ValueAnimator;->setDurationScale(F)V
-Landroid/app/Activity;->convertFromTranslucent()V
-Landroid/app/Activity;->convertToTranslucent(Landroid/app/Activity$TranslucentConversionListener;Landroid/app/ActivityOptions;)Z
Landroid/app/Activity;->getActivityOptions()Landroid/app/ActivityOptions;
Landroid/app/Activity;->getActivityToken()Landroid/os/IBinder;
Landroid/app/Activity;->mActivityInfo:Landroid/content/pm/ActivityInfo;
-Landroid/app/ActivityManager;->addOnUidImportanceListener(Landroid/app/ActivityManager$OnUidImportanceListener;I)V
Landroid/app/ActivityManager;->clearApplicationUserData(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)Z
-Landroid/app/ActivityManager;->forceStopPackage(Ljava/lang/String;)V
-Landroid/app/ActivityManager;->getCurrentUser()I
-Landroid/app/ActivityManager;->getPackageImportance(Ljava/lang/String;)I
+Landroid/app/ActivityManager;->getMaxRecentTasksStatic()I
Landroid/app/ActivityManager;->getService()Landroid/app/IActivityManager;
Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton;
Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
@@ -23,9 +16,9 @@
Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
+Landroid/app/ActivityManager;->PROCESS_STATE_IMPORTANT_BACKGROUND:I
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
-Landroid/app/ActivityManager;->removeOnUidImportanceListener(Landroid/app/ActivityManager$OnUidImportanceListener;)V
Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
Landroid/app/ActivityManager$RunningAppProcessInfo;->processState:I
Landroid/app/Activity;->mApplication:Landroid/app/Application;
@@ -118,16 +111,11 @@
Landroid/app/ActivityThread$ServiceArgsData;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
Landroid/app/ActivityThread;->startActivityNow(Landroid/app/Activity;Ljava/lang/String;Landroid/content/Intent;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/Activity$NonConfigurationInstances;)Landroid/app/Activity;
-Landroid/app/admin/DevicePolicyManager;->getDeviceOwnerComponentOnAnyUser()Landroid/content/ComponentName;
-Landroid/app/admin/DevicePolicyManager;->getDeviceOwner()Ljava/lang/String;
-Landroid/app/admin/DevicePolicyManager;->getProfileOwner()Landroid/content/ComponentName;
Landroid/app/admin/DevicePolicyManager;->getTrustAgentConfiguration(Landroid/content/ComponentName;Landroid/content/ComponentName;I)Ljava/util/List;
-Landroid/app/admin/DevicePolicyManager;->notifyPendingSystemUpdate(J)V
-Landroid/app/admin/DevicePolicyManager;->notifyPendingSystemUpdate(JZ)V
Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z
-Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;)Z
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
+Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
@@ -136,8 +124,6 @@
Landroid/app/AlarmManager;->FLAG_STANDALONE:I
Landroid/app/AlarmManager;->FLAG_WAKE_FROM_IDLE:I
Landroid/app/AlarmManager;->mService:Landroid/app/IAlarmManager;
-Landroid/app/AlarmManager;->set(IJJJLandroid/app/AlarmManager$OnAlarmListener;Landroid/os/Handler;Landroid/os/WorkSource;)V
-Landroid/app/AlarmManager;->set(IJJJLandroid/app/PendingIntent;Landroid/os/WorkSource;)V
Landroid/app/AlarmManager;->WINDOW_EXACT:J
Landroid/app/AlarmManager;->WINDOW_HEURISTIC:J
Landroid/app/AlertDialog$Builder;->P:Lcom/android/internal/app/AlertController$AlertParams;
@@ -161,8 +147,6 @@
Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
-Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;)I
-Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;I)I
Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager;
Landroid/app/AppOpsManager;->checkOp(IILjava/lang/String;)I
Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I
@@ -175,46 +159,20 @@
Landroid/app/AppOpsManager;->OP_POST_NOTIFICATION:I
Landroid/app/AppOpsManager;->OP_READ_PHONE_STATE:I
Landroid/app/AppOpsManager;->OP_READ_SMS:I
-Landroid/app/AppOpsManager;->OP_SYSTEM_ALERT_WINDOW:I
Landroid/app/AppOpsManager;->OP_WIFI_SCAN:I
Landroid/app/AppOpsManager;->OP_WRITE_SMS:I
Landroid/app/AppOpsManager;->permissionToOpCode(Ljava/lang/String;)I
-Landroid/app/AppOpsManager;->setMode(IILjava/lang/String;I)V
Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I
Landroid/app/backup/BackupDataInput$EntityHeader;->dataSize:I
Landroid/app/backup/BackupDataInput$EntityHeader;->key:Ljava/lang/String;
-Landroid/app/backup/BackupDataInput;-><init>(Ljava/io/FileDescriptor;)V
Landroid/app/backup/BackupDataInputStream;->dataSize:I
Landroid/app/backup/BackupDataInputStream;->key:Ljava/lang/String;
-Landroid/app/backup/BackupDataOutput;-><init>(Ljava/io/FileDescriptor;)V
Landroid/app/backup/BackupDataOutput;->mBackupWriter:J
Landroid/app/backup/BackupHelperDispatcher$Header;->chunkSize:I
Landroid/app/backup/BackupHelperDispatcher$Header;->keyPrefix:Ljava/lang/String;
-Landroid/app/backup/BackupManager;->backupNow()V
-Landroid/app/backup/BackupManager;->beginRestoreSession()Landroid/app/backup/RestoreSession;
-Landroid/app/backup/BackupManager;->cancelBackups()V
-Landroid/app/backup/BackupManager;->getAvailableRestoreToken(Ljava/lang/String;)J
-Landroid/app/backup/BackupManager;->getCurrentTransport()Ljava/lang/String;
-Landroid/app/backup/BackupManager;->isBackupEnabled()Z
-Landroid/app/backup/BackupManager;->listAllTransports()[Ljava/lang/String;
-Landroid/app/backup/BackupManagerMonitor;-><init>()V
-Landroid/app/backup/BackupManager;->requestBackup([Ljava/lang/String;Landroid/app/backup/BackupObserver;Landroid/app/backup/BackupManagerMonitor;I)I
-Landroid/app/backup/BackupManager;->selectBackupTransport(Landroid/content/ComponentName;Landroid/app/backup/SelectBackupTransportCallback;)V
-Landroid/app/backup/BackupManager;->selectBackupTransport(Ljava/lang/String;)Ljava/lang/String;
-Landroid/app/backup/BackupManager;->setAutoRestore(Z)V
-Landroid/app/backup/BackupManager;->setBackupEnabled(Z)V
-Landroid/app/backup/BackupManager;->updateTransportAttributes(Landroid/content/ComponentName;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;)V
-Landroid/app/backup/BackupObserver;-><init>()V
-Landroid/app/backup/BackupTransport;-><init>()V
Landroid/app/backup/FullBackup;->backupToTar(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I
Landroid/app/backup/FullBackupDataOutput;->addSize(J)V
Landroid/app/backup/FullBackupDataOutput;->mData:Landroid/app/backup/BackupDataOutput;
-Landroid/app/backup/RestoreDescription;-><init>(Ljava/lang/String;I)V
-Landroid/app/backup/RestoreSession;->endRestoreSession()V
-Landroid/app/backup/RestoreSession;->getAvailableRestoreSets(Landroid/app/backup/RestoreObserver;)I
-Landroid/app/backup/RestoreSession;->restoreAll(JLandroid/app/backup/RestoreObserver;)I
-Landroid/app/backup/RestoreSet;-><init>(Ljava/lang/String;Ljava/lang/String;J)V
-Landroid/app/backup/SelectBackupTransportCallback;-><init>()V
Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo;
Landroid/app/ContentProviderHolder;-><init>(Landroid/content/pm/ProviderInfo;)V
Landroid/app/ContentProviderHolder;->provider:Landroid/content/IContentProvider;
@@ -246,6 +204,7 @@
Landroid/app/Dialog;->mShowMessage:Landroid/os/Message;
Landroid/app/DownloadManager$Request;->mUri:Landroid/net/Uri;
Landroid/app/FragmentManagerImpl;->mAdded:Ljava/util/ArrayList;
+Landroid/app/FragmentManagerImpl;->noteStateNotSaved()V
Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl;
Landroid/app/Fragment;->mWho:Ljava/lang/String;
Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
@@ -271,8 +230,6 @@
Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V
Landroid/app/INotificationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/INotificationManager;
Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/app/InstantAppResolverService;-><init>()V
-Landroid/app/InstantAppResolverService$InstantAppResolutionCallback;->onInstantAppResolveInfo(Ljava/util/List;)V
Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult;
Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult;
Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/Instrumentation$ActivityResult;
@@ -312,7 +269,6 @@
Landroid/app/NativeActivity;->showIme(I)V
Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder;
-Landroid/app/Notification;->EXTRA_SUBSTITUTE_APP_NAME:Ljava/lang/String;
Landroid/app/Notification;->isGroupSummary()Z
Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
Landroid/app/NotificationManager;->notifyAsUser(Ljava/lang/String;ILandroid/app/Notification;Landroid/os/UserHandle;)V
@@ -348,13 +304,10 @@
Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
Landroid/app/StatusBarManager;->expandSettingsPanel()V
Landroid/app/StatusBarManager;->getService()Lcom/android/internal/statusbar/IStatusBarService;
+Landroid/app/TaskStackListener;-><init>()V
Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/app/usage/UsageStatsManager;->getAppStandbyBucket(Ljava/lang/String;)I
-Landroid/app/usage/UsageStatsManager;->getAppStandbyBuckets()Ljava/util/Map;
Landroid/app/usage/UsageStatsManager;->mService:Landroid/app/usage/IUsageStatsManager;
-Landroid/app/usage/UsageStatsManager;->setAppStandbyBuckets(Ljava/util/Map;)V
-Landroid/app/usage/UsageStatsManager;->whitelistAppTemporarily(Ljava/lang/String;JLandroid/os/UserHandle;)V
Landroid/app/usage/UsageStats;->mLastEvent:I
Landroid/app/WallpaperColors;->getColorHints()I
Landroid/app/WallpaperManager;->getBitmap()Landroid/graphics/Bitmap;
@@ -368,37 +321,25 @@
Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;)V
Landroid/appwidget/AppWidgetManager;->mService:Lcom/android/internal/appwidget/IAppWidgetService;
Landroid/bluetooth/BluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z
-Landroid/bluetooth/BluetoothAdapter;->disableBLE()Z
Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z
-Landroid/bluetooth/BluetoothAdapter;->enableBLE()Z
-Landroid/bluetooth/BluetoothAdapter;->enableNoAutoConnect()Z
Landroid/bluetooth/BluetoothAdapter;->getDiscoverableTimeout()I
-Landroid/bluetooth/BluetoothAdapter;->isBleScanAlwaysAvailable()Z
-Landroid/bluetooth/BluetoothAdapter;->isLeEnabled()Z
Landroid/bluetooth/BluetoothAdapter;->mService:Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/BluetoothAdapter;->setScanMode(II)Z
Landroid/bluetooth/BluetoothAdapter;->setScanMode(I)Z
-Landroid/bluetooth/BluetoothDevice;->cancelBondProcess()Z
Landroid/bluetooth/BluetoothDevice;->createBond(I)Z
Landroid/bluetooth/BluetoothDevice;->getAliasName()Ljava/lang/String;
-Landroid/bluetooth/BluetoothDevice;->isConnected()Z
-Landroid/bluetooth/BluetoothDevice;->isEncrypted()Z
-Landroid/bluetooth/BluetoothDevice;->removeBond()Z
-Landroid/bluetooth/BluetoothDevice;->setPhonebookAccessPermission(I)Z
Landroid/bluetooth/BluetoothGattCharacteristic;->mInstance:I
Landroid/bluetooth/BluetoothGattCharacteristic;->mService:Landroid/bluetooth/BluetoothGattService;
Landroid/bluetooth/BluetoothGattDescriptor;->mCharacteristic:Landroid/bluetooth/BluetoothGattCharacteristic;
Landroid/bluetooth/BluetoothGattDescriptor;->mInstance:I
Landroid/bluetooth/BluetoothGatt;->refresh()Z
Landroid/bluetooth/BluetoothHeadset;->close()V
-Landroid/bluetooth/BluetoothHeadset;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid;
Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
-Landroid/bluetooth/le/BluetoothLeScanner;->startScanFromSource(Ljava/util/List;Landroid/bluetooth/le/ScanSettings;Landroid/os/WorkSource;Landroid/bluetooth/le/ScanCallback;)V
-Landroid/bluetooth/le/ScanSettings$Builder;->setScanResultType(I)Landroid/bluetooth/le/ScanSettings$Builder;
+Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord;
Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
@@ -420,18 +361,11 @@
Landroid/content/ContentResolver;->mPackageName:Ljava/lang/String;
Landroid/content/ContentValues;-><init>(Ljava/util/HashMap;)V
Landroid/content/ContentValues;->mValues:Ljava/util/HashMap;
-Landroid/content/Context;->bindServiceAsUser(Landroid/content/Intent;Landroid/content/ServiceConnection;ILandroid/os/UserHandle;)Z
-Landroid/content/Context;->createCredentialProtectedStorageContext()Landroid/content/Context;
-Landroid/content/Context;->createPackageContextAsUser(Ljava/lang/String;ILandroid/os/UserHandle;)Landroid/content/Context;
Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
Landroid/content/Context;->getThemeResId()I
-Landroid/content/Context;->isCredentialProtectedStorage()Z
-Landroid/content/Context;->PERSISTENT_DATA_BLOCK_SERVICE:Ljava/lang/String;
Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;I)V
-Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;Landroid/os/Bundle;)V
Landroid/content/Context;->sendOrderedBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;ILandroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V
Landroid/content/Context;->sendOrderedBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V
-Landroid/content/ContextWrapper;->createCredentialProtectedStorageContext()Landroid/content/Context;
Landroid/content/ContextWrapper;->getDisplay()Landroid/view/Display;
Landroid/content/ContextWrapper;->mBase:Landroid/content/Context;
Landroid/content/CursorLoader;->mCancellationSignal:Landroid/os/CancellationSignal;
@@ -446,26 +380,17 @@
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList;
-Landroid/content/IntentFilter;->setOrder(I)V
Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
Landroid/content/pm/ActivityInfo;->resizeMode:I
Landroid/content/pm/ApplicationInfo;->enabledSetting:I
Landroid/content/pm/ApplicationInfo;->getBaseResourcePath()Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->installLocation:I
Landroid/content/pm/ApplicationInfo;->isForwardLocked()Z
-Landroid/content/pm/ApplicationInfo;->isInstantApp()Z
-Landroid/content/pm/ApplicationInfo;->isPrivilegedApp()Z
Landroid/content/pm/ApplicationInfo;->primaryCpuAbi:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->privateFlags:I
Landroid/content/pm/ApplicationInfo;->scanPublicSourceDir:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->scanSourceDir:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String;
-Landroid/content/pm/ApplicationInfo;->targetSandboxVersion:I
-Landroid/content/pm/InstantAppIntentFilter;-><init>(Ljava/lang/String;Ljava/util/List;)V
-Landroid/content/pm/InstantAppResolveInfo;->getPackageName()Ljava/lang/String;
-Landroid/content/pm/InstantAppResolveInfo;-><init>(Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;Ljava/lang/String;Ljava/util/List;I)V
-Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;->getDigestPrefix()[I
-Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;-><init>(Ljava/lang/String;)V
Landroid/content/pm/IPackageManager;->getInstallLocation()I
Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
Landroid/content/pm/IPackageManager;->setApplicationEnabledSetting(Ljava/lang/String;IIILjava/lang/String;)V
@@ -479,10 +404,6 @@
Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo;
Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
-Landroid/content/pm/PackageInstaller$SessionParams;->setAllocateAggressive(Z)V
-Landroid/content/pm/PackageInstaller$SessionParams;->setGrantedRuntimePermissions([Ljava/lang/String;)V
-Landroid/content/pm/PackageInstaller$SessionParams;->setInstallAsInstantApp(Z)V
-Landroid/content/pm/PackageManager;->addOnPermissionsChangeListener(Landroid/content/pm/PackageManager$OnPermissionsChangedListener;)V
Landroid/content/pm/PackageManager;->buildRequestPermissionsIntent([Ljava/lang/String;)Landroid/content/Intent;
Landroid/content/pm/PackageManager;->freeStorageAndNotify(JLandroid/content/pm/IPackageDataObserver;)V
Landroid/content/pm/PackageManager;->freeStorageAndNotify(Ljava/lang/String;JLandroid/content/pm/IPackageDataObserver;)V
@@ -496,8 +417,6 @@
Landroid/content/pm/PackageManager;->movePackage(Ljava/lang/String;Landroid/os/storage/VolumeInfo;)I
Landroid/content/pm/PackageManager;->NO_NATIVE_LIBRARIES:I
Landroid/content/pm/PackageManager;->queryBroadcastReceivers(Landroid/content/Intent;II)Ljava/util/List;
-Landroid/content/pm/PackageManager;->removeOnPermissionsChangeListener(Landroid/content/pm/PackageManager$OnPermissionsChangedListener;)V
-Landroid/content/pm/PackageManager;->verifyIntentFilter(IILjava/util/List;)V
Landroid/content/pm/PackageParser$Activity;->info:Landroid/content/pm/ActivityInfo;
Landroid/content/pm/PackageParser$ActivityIntentInfo;->activity:Landroid/content/pm/PackageParser$Activity;
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
@@ -527,6 +446,7 @@
Landroid/content/pm/PackageUserState;-><init>()V
Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
Landroid/content/pm/ResolveInfo;->instantAppAvailable:Z
+Landroid/content/pm/ShortcutManager;->mService:Landroid/content/pm/IShortcutService;
Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
Landroid/content/pm/UserInfo;->id:I
Landroid/content/pm/UserInfo;->isPrimary()Z
@@ -576,6 +496,7 @@
Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
Landroid/content/res/Resources;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
Landroid/content/res/Resources;->mResourcesImpl:Landroid/content/res/ResourcesImpl;
+Landroid/content/res/Resources;->mSystem:Landroid/content/res/Resources;
Landroid/content/res/Resources;->mTmpValue:Landroid/util/TypedValue;
Landroid/content/res/Resources;->mTypedArrayPool:Landroid/util/Pools$SynchronizedPool;
Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
@@ -677,6 +598,7 @@
Landroid/graphics/drawable/StateListDrawable;->extractStateSet(Landroid/util/AttributeSet;)[I
Landroid/graphics/drawable/StateListDrawable;->getStateCount()I
Landroid/graphics/drawable/StateListDrawable;->getStateDrawable(I)Landroid/graphics/drawable/Drawable;
+Landroid/graphics/drawable/StateListDrawable;->getStateDrawableIndex([I)I
Landroid/graphics/drawable/StateListDrawable;->getStateSet(I)[I
Landroid/graphics/drawable/StateListDrawable;->mStateListState:Landroid/graphics/drawable/StateListDrawable$StateListState;
Landroid/graphics/drawable/StateListDrawable;->updateStateFromTypedArray(Landroid/content/res/TypedArray;)V
@@ -707,6 +629,7 @@
Landroid/graphics/SurfaceTexture;->mSurfaceTexture:J
Landroid/graphics/SurfaceTexture;->nativeDetachFromGLContext()I
Landroid/graphics/SurfaceTexture;->postEventFromNative(Ljava/lang/ref/WeakReference;)V
+Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;Ljava/lang/String;II)Landroid/graphics/Typeface;
Landroid/graphics/Typeface;->mStyle:I
Landroid/graphics/Typeface;->sDefaults:[Landroid/graphics/Typeface;
Landroid/graphics/Typeface;->setDefault(Landroid/graphics/Typeface;)V
@@ -719,7 +642,6 @@
Landroid/hardware/Camera;->mNativeContext:J
Landroid/hardware/Camera;->openLegacy(II)Landroid/hardware/Camera;
Landroid/hardware/Camera;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
-Landroid/hardware/display/DisplayManager;->getStableDisplaySize()Landroid/graphics/Point;
Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay;
Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
Landroid/hardware/HardwareBuffer;-><init>(J)V
@@ -728,43 +650,7 @@
Landroid/hardware/input/IInputManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager;
Landroid/hardware/input/InputManager;->mIm:Landroid/hardware/input/IInputManager;
-Landroid/hardware/location/ContextHubInfo;->getId()I
-Landroid/hardware/location/ContextHubInfo;->getMaxPacketLengthBytes()I
-Landroid/hardware/location/ContextHubManager$Callback;-><init>()V
-Landroid/hardware/location/ContextHubManager;->findNanoAppOnHub(ILandroid/hardware/location/NanoAppFilter;)[I
-Landroid/hardware/location/ContextHubManager;->getContextHubHandles()[I
-Landroid/hardware/location/ContextHubManager;->getContextHubInfo(I)Landroid/hardware/location/ContextHubInfo;
-Landroid/hardware/location/ContextHubManager;->getNanoAppInstanceInfo(I)Landroid/hardware/location/NanoAppInstanceInfo;
-Landroid/hardware/location/ContextHubManager;->loadNanoApp(ILandroid/hardware/location/NanoApp;)I
-Landroid/hardware/location/ContextHubManager;->registerCallback(Landroid/hardware/location/ContextHubManager$Callback;)I
-Landroid/hardware/location/ContextHubManager;->sendMessage(IILandroid/hardware/location/ContextHubMessage;)I
-Landroid/hardware/location/ContextHubManager;->unloadNanoApp(I)I
-Landroid/hardware/location/ContextHubMessage;->getData()[B
-Landroid/hardware/location/ContextHubMessage;->getMsgType()I
-Landroid/hardware/location/ContextHubMessage;->getVersion()I
-Landroid/hardware/location/ContextHubMessage;-><init>(II[B)V
-Landroid/hardware/location/GeofenceHardware;->addGeofence(IILandroid/hardware/location/GeofenceHardwareRequest;Landroid/hardware/location/GeofenceHardwareCallback;)Z
-Landroid/hardware/location/GeofenceHardwareCallback;-><init>()V
-Landroid/hardware/location/GeofenceHardwareCallback;->onGeofenceAdd(II)V
-Landroid/hardware/location/GeofenceHardwareCallback;->onGeofenceRemove(II)V
-Landroid/hardware/location/GeofenceHardwareCallback;->onGeofenceTransition(IILandroid/location/Location;JI)V
-Landroid/hardware/location/GeofenceHardware;->getMonitoringTypes()[I
-Landroid/hardware/location/GeofenceHardware;->getStatusOfMonitoringType(I)I
-Landroid/hardware/location/GeofenceHardwareMonitorCallback;-><init>()V
-Landroid/hardware/location/GeofenceHardwareMonitorCallback;->onMonitoringSystemChange(IZLandroid/location/Location;)V
-Landroid/hardware/location/GeofenceHardware;->registerForMonitorStateChangeCallback(ILandroid/hardware/location/GeofenceHardwareMonitorCallback;)Z
-Landroid/hardware/location/GeofenceHardware;->removeGeofence(II)Z
-Landroid/hardware/location/GeofenceHardwareRequest;->createCircularGeofence(DDD)Landroid/hardware/location/GeofenceHardwareRequest;
-Landroid/hardware/location/GeofenceHardwareRequest;->setLastTransition(I)V
-Landroid/hardware/location/GeofenceHardwareRequest;->setMonitorTransitions(I)V
-Landroid/hardware/location/GeofenceHardwareRequest;->setNotificationResponsiveness(I)V
-Landroid/hardware/location/GeofenceHardwareRequest;->setUnknownTimer(I)V
-Landroid/hardware/location/NanoAppFilter;-><init>(JIIJ)V
-Landroid/hardware/location/NanoApp;-><init>(J[B)V
-Landroid/hardware/location/NanoAppInstanceInfo;->getAppId()J
-Landroid/hardware/location/NanoAppInstanceInfo;->getAppVersion()I
-Landroid/hardware/location/NanoAppInstanceInfo;->getHandle()I
-Landroid/hardware/location/NanoAppInstanceInfo;->getName()Ljava/lang/String;
+Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V
Landroid/hardware/SerialPort;->mNativeContext:I
Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->confidenceLevel:I
Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;-><init>(II)V
@@ -799,17 +685,32 @@
Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchSensorEvent(I[FIJ)V
Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J
+Landroid/hardware/usb/UsbManager;->getPorts()[Landroid/hardware/usb/UsbPort;
+Landroid/hardware/usb/UsbManager;->getPortStatus(Landroid/hardware/usb/UsbPort;)Landroid/hardware/usb/UsbPortStatus;
Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
+Landroid/hardware/usb/UsbManager;->setPortRoles(Landroid/hardware/usb/UsbPort;II)V
+Landroid/hardware/usb/UsbPortStatus;->getCurrentDataRole()I
+Landroid/hardware/usb/UsbPortStatus;->isConnected()Z
+Landroid/hardware/usb/UsbPortStatus;->isRoleCombinationSupported(II)Z
Landroid/hardware/usb/UsbRequest;->mNativeContext:J
+Landroid/icu/impl/CurrencyData;-><init>()V
Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
+Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
+Landroid/icu/text/ArabicShaping;->isTailChar(C)Z
+Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z
Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateIntervalFormat;-><init>()V
Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;-><init>()V
Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
@@ -821,13 +722,23 @@
Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V
+Landroid/icu/text/SpoofChecker$ScriptSet;-><init>()V
+Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z
+Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V
Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;-><init>()V
+Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator;
+Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String;
+Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
+Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
@@ -839,15 +750,12 @@
Landroid/location/Country;->getSource()I
Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String;
Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale;
+Landroid/location/IFusedProvider$Stub;-><init>()V
+Landroid/location/IGeocodeProvider$Stub;-><init>()V
+Landroid/location/IGeofenceProvider$Stub;-><init>()V
+Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/LocationManager;->mService:Landroid/location/ILocationManager;
-Landroid/location/LocationManager;->requestLocationUpdates(Landroid/location/LocationRequest;Landroid/location/LocationListener;Landroid/os/Looper;)V
-Landroid/location/LocationRequest;->createFromDeprecatedProvider(Ljava/lang/String;JFZ)Landroid/location/LocationRequest;
-Landroid/location/LocationRequest;->setHideFromAppOps(Z)V
-Landroid/location/LocationRequest;->setWorkSource(Landroid/os/WorkSource;)V
-Landroid/location/Location;->setIsFromMockProvider(Z)V
-Landroid/Manifest$permission;->REAL_GET_TASKS:Ljava/lang/String;
-Landroid/media/AudioAttributes$Builder;->setInternalCapturePreset(I)Landroid/media/AudioAttributes$Builder;
Landroid/media/AudioAttributes;->mContentType:I
Landroid/media/AudioAttributes;->mFlags:I
Landroid/media/AudioAttributes;->mFormattedTags:Ljava/lang/String;
@@ -855,13 +763,12 @@
Landroid/media/AudioAttributes;->mUsage:I
Landroid/media/AudioDevicePortConfig;-><init>(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V
Landroid/media/AudioDevicePort;-><init>(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V
-Landroid/media/AudioFocusInfo;->getClientId()Ljava/lang/String;
-Landroid/media/AudioFocusInfo;->getClientUid()I
-Landroid/media/AudioFocusInfo;->getLossReceived()I
Landroid/media/AudioFormat;-><init>(IIII)V
Landroid/media/AudioFormat;->mChannelMask:I
Landroid/media/AudioFormat;->mEncoding:I
Landroid/media/AudioFormat;->mSampleRate:I
+Landroid/media/audiofx/AudioEffect;->command(I[B[B)I
+Landroid/media/audiofx/AudioEffect;->getParameter([I[B)I
Landroid/media/audiofx/AudioEffect;-><init>(Ljava/util/UUID;Ljava/util/UUID;II)V
Landroid/media/AudioGainConfig;-><init>(ILandroid/media/AudioGain;II[II)V
Landroid/media/AudioGainConfig;->mChannelMask:I
@@ -872,33 +779,21 @@
Landroid/media/AudioGain;-><init>(IIIIIIIII)V
Landroid/media/AudioHandle;-><init>(I)V
Landroid/media/AudioHandle;->mId:I
-Landroid/media/AudioManager;->abandonAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;)I
+Landroid/media/AudioManager;->forceVolumeControlStream(I)V
Landroid/media/AudioManager;->getOutputLatency(I)I
Landroid/media/AudioManager;->getService()Landroid/media/IAudioService;
Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap;
-Landroid/media/AudioManager;->registerAudioPolicy(Landroid/media/audiopolicy/AudioPolicy;)I
-Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioFocusRequest;Landroid/media/audiopolicy/AudioPolicy;)I
-Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;II)I
-Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;IILandroid/media/audiopolicy/AudioPolicy;)I
Landroid/media/AudioManager;->setMasterMute(ZI)V
Landroid/media/AudioManager;->STREAM_BLUETOOTH_SCO:I
Landroid/media/AudioManager;->STREAM_SYSTEM_ENFORCED:I
Landroid/media/AudioManager;->STREAM_TTS:I
-Landroid/media/AudioManager;->unregisterAudioPolicyAsync(Landroid/media/audiopolicy/AudioPolicy;)V
Landroid/media/AudioMixPortConfig;-><init>(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V
Landroid/media/AudioMixPort;-><init>(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V
Landroid/media/AudioPatch;-><init>(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V
Landroid/media/AudioPatch;->mHandle:Landroid/media/AudioHandle;
-Landroid/media/audiopolicy/AudioMix$Builder;->build()Landroid/media/audiopolicy/AudioMix;
-Landroid/media/audiopolicy/AudioMix$Builder;-><init>(Landroid/media/audiopolicy/AudioMixingRule;)V
-Landroid/media/audiopolicy/AudioMix$Builder;->setFormat(Landroid/media/AudioFormat;)Landroid/media/audiopolicy/AudioMix$Builder;
-Landroid/media/audiopolicy/AudioMix$Builder;->setRouteFlags(I)Landroid/media/audiopolicy/AudioMix$Builder;
Landroid/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion;->mAttr:Landroid/media/AudioAttributes;
Landroid/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion;->mIntProp:I
Landroid/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion;->mRule:I
-Landroid/media/audiopolicy/AudioMixingRule$Builder;->addRule(Landroid/media/AudioAttributes;I)Landroid/media/audiopolicy/AudioMixingRule$Builder;
-Landroid/media/audiopolicy/AudioMixingRule$Builder;->build()Landroid/media/audiopolicy/AudioMixingRule;
-Landroid/media/audiopolicy/AudioMixingRule$Builder;-><init>()V
Landroid/media/audiopolicy/AudioMixingRule;->mCriteria:Ljava/util/ArrayList;
Landroid/media/audiopolicy/AudioMix;->mCallbackFlags:I
Landroid/media/audiopolicy/AudioMix;->mDeviceAddress:Ljava/lang/String;
@@ -907,13 +802,6 @@
Landroid/media/audiopolicy/AudioMix;->mMixType:I
Landroid/media/audiopolicy/AudioMix;->mRouteFlags:I
Landroid/media/audiopolicy/AudioMix;->mRule:Landroid/media/audiopolicy/AudioMixingRule;
-Landroid/media/audiopolicy/AudioPolicy$AudioPolicyFocusListener;-><init>()V
-Landroid/media/audiopolicy/AudioPolicy$Builder;->addMix(Landroid/media/audiopolicy/AudioMix;)Landroid/media/audiopolicy/AudioPolicy$Builder;
-Landroid/media/audiopolicy/AudioPolicy$Builder;->build()Landroid/media/audiopolicy/AudioPolicy;
-Landroid/media/audiopolicy/AudioPolicy$Builder;-><init>(Landroid/content/Context;)V
-Landroid/media/audiopolicy/AudioPolicy$Builder;->setAudioPolicyFocusListener(Landroid/media/audiopolicy/AudioPolicy$AudioPolicyFocusListener;)V
-Landroid/media/audiopolicy/AudioPolicy$Builder;->setLooper(Landroid/os/Looper;)Landroid/media/audiopolicy/AudioPolicy$Builder;
-Landroid/media/audiopolicy/AudioPolicy;->createAudioRecordSink(Landroid/media/audiopolicy/AudioMix;)Landroid/media/AudioRecord;
Landroid/media/AudioPortConfig;-><init>(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V
Landroid/media/AudioPortConfig;->mChannelMask:I
Landroid/media/AudioPortConfig;->mConfigMask:I
@@ -928,9 +816,12 @@
Landroid/media/AudioPort;->mGains:[Landroid/media/AudioGain;
Landroid/media/AudioPort;->mHandle:Landroid/media/AudioHandle;
Landroid/media/AudioPort;->mRole:I
+Landroid/media/AudioRecordingConfiguration;->getClientPackageName()Ljava/lang/String;
+Landroid/media/AudioRecordingConfiguration;->getClientUid()I
Landroid/media/AudioRecord;->mNativeCallbackCookie:J
Landroid/media/AudioRecord;->mNativeDeviceCallback:J
Landroid/media/AudioRecord;->mNativeRecorderInJavaObj:J
+Landroid/media/AudioRecord;->native_release()V
Landroid/media/AudioRecord;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
Landroid/media/AudioSystem;->dynamicPolicyCallbackFromNative(ILjava/lang/String;I)V
Landroid/media/AudioSystem;->errorCallbackFromNative(I)V
@@ -938,15 +829,18 @@
Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I
Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V
Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
+Landroid/media/AudioTrack;->deferred_connect(J)V
Landroid/media/AudioTrack;->getLatency()I
Landroid/media/AudioTrack;->mJniData:J
Landroid/media/AudioTrack;->mNativeTrackInJavaObj:J
Landroid/media/AudioTrack;->mStreamType:I
+Landroid/media/AudioTrack;->native_release()V
Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J
Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V
+Landroid/media/MediaCodec$CodecException;-><init>(IILjava/lang/String;)V
Landroid/media/MediaCodec;->releaseOutputBuffer(IZZJ)V
Landroid/media/MediaFile;->FIRST_AUDIO_FILE_TYPE:I
Landroid/media/MediaFile;->getFileType(Ljava/lang/String;)Landroid/media/MediaFile$MediaFileType;
@@ -970,7 +864,6 @@
Landroid/media/MediaPlayer;->setDataSource(Ljava/lang/String;Ljava/util/Map;Ljava/util/List;)V
Landroid/media/MediaPlayer;->setDataSource(Ljava/lang/String;Ljava/util/Map;)V
Landroid/media/MediaPlayer;->setRetransmitEndpoint(Ljava/net/InetSocketAddress;)V
-Landroid/media/MediaRecorder$AudioSource;->RADIO_TUNER:I
Landroid/media/MediaRouter$RouteInfo;->getStatusCode()I
Landroid/media/MediaRouter$RouteInfo;->STATUS_CONNECTING:I
Landroid/media/MediaRouter;->selectRouteInt(ILandroid/media/MediaRouter$RouteInfo;Z)V
@@ -1017,19 +910,6 @@
Landroid/media/VolumeShaper$State;-><init>(FF)V
Landroid/media/VolumeShaper$State;->mVolume:F
Landroid/media/VolumeShaper$State;->mXOffset:F
-Landroid/metrics/LogMaker;->getCategory()I
-Landroid/metrics/LogMaker;->getCounterBucket()J
-Landroid/metrics/LogMaker;->getCounterName()Ljava/lang/String;
-Landroid/metrics/LogMaker;->getCounterValue()I
-Landroid/metrics/LogMaker;->getTimestamp()J
-Landroid/metrics/LogMaker;->isLongCounterBucket()Z
-Landroid/metrics/LogMaker;->serialize()[Ljava/lang/Object;
-Landroid/metrics/MetricsReader;->checkpoint()V
-Landroid/metrics/MetricsReader;->hasNext()Z
-Landroid/metrics/MetricsReader;-><init>()V
-Landroid/metrics/MetricsReader;->next()Landroid/metrics/LogMaker;
-Landroid/metrics/MetricsReader;->read(J)V
-Landroid/metrics/MetricsReader;->reset()V
Landroid/net/ConnectivityManager;->ACTION_TETHER_STATE_CHANGED:Ljava/lang/String;
Landroid/net/ConnectivityManager;->EXTRA_ACTIVE_TETHER:Ljava/lang/String;
Landroid/net/ConnectivityManager;->getActiveLinkProperties()Landroid/net/LinkProperties;
@@ -1040,14 +920,9 @@
Landroid/net/ConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
Landroid/net/ConnectivityManager;->isNetworkSupported(I)Z
Landroid/net/ConnectivityManager;->isNetworkTypeMobile(I)Z
-Landroid/net/ConnectivityManager;->isTetheringSupported()Z
Landroid/net/ConnectivityManager;->mService:Landroid/net/IConnectivityManager;
-Landroid/net/ConnectivityManager$OnStartTetheringCallback;-><init>()V
Landroid/net/ConnectivityManager;->requestRouteToHostAddress(ILjava/net/InetAddress;)Z
Landroid/net/ConnectivityManager;->requestRouteToHost(II)Z
-Landroid/net/ConnectivityManager;->startTethering(IZLandroid/net/ConnectivityManager$OnStartTetheringCallback;Landroid/os/Handler;)V
-Landroid/net/ConnectivityManager;->startTethering(IZLandroid/net/ConnectivityManager$OnStartTetheringCallback;)V
-Landroid/net/ConnectivityManager;->stopTethering(I)V
Landroid/net/ConnectivityManager;->TYPE_MOBILE_CBS:I
Landroid/net/ConnectivityManager;->TYPE_MOBILE_EMERGENCY:I
Landroid/net/ConnectivityManager;->TYPE_MOBILE_FOTA:I
@@ -1068,12 +943,7 @@
Landroid/net/LocalSocketImpl;->outboundFileDescriptors:[Ljava/io/FileDescriptor;
Landroid/net/NetworkCapabilities;->getCapabilities()[I
Landroid/net/NetworkCapabilities;->getTransportTypes()[I
-Landroid/net/NetworkKey;-><init>(Landroid/net/WifiKey;)V
Landroid/net/NetworkPolicyManager;->mService:Landroid/net/INetworkPolicyManager;
-Landroid/net/NetworkRecommendationProvider;-><init>(Landroid/content/Context;Ljava/util/concurrent/Executor;)V
-Landroid/net/NetworkScoreManager;->clearScores()Z
-Landroid/net/NetworkScoreManager;->getActiveScorerPackage()Ljava/lang/String;
-Landroid/net/NetworkScoreManager;->updateScores([Landroid/net/ScoredNetwork;)Z
Landroid/net/NetworkStats;->capacity:I
Landroid/net/NetworkStats;->defaultNetwork:[I
Landroid/net/NetworkStats;->iface:[Ljava/lang/String;
@@ -1089,12 +959,6 @@
Landroid/net/NetworkStats;->txPackets:[J
Landroid/net/NetworkStats;->uid:[I
Landroid/net/ProxyInfo;-><init>(Ljava/lang/String;ILjava/lang/String;)V
-Landroid/net/RssiCurve;-><init>(II[BI)V
-Landroid/net/RssiCurve;-><init>(II[B)V
-Landroid/net/RssiCurve;->lookupScore(IZ)B
-Landroid/net/ScoredNetwork;-><init>(Landroid/net/NetworkKey;Landroid/net/RssiCurve;)V
-Landroid/net/ScoredNetwork;-><init>(Landroid/net/NetworkKey;Landroid/net/RssiCurve;ZLandroid/os/Bundle;)V
-Landroid/net/ScoredNetwork;-><init>(Landroid/net/NetworkKey;Landroid/net/RssiCurve;Z)V
Landroid/net/SSLCertificateSocketFactory;->castToOpenSSLSocket(Ljava/net/Socket;)Lcom/android/org/conscrypt/OpenSSLSocketImpl;
Landroid/net/SSLCertificateSocketFactory;->getAlpnSelectedProtocol(Ljava/net/Socket;)[B
Landroid/net/SSLCertificateSocketFactory;->getDelegate()Ljavax/net/ssl/SSLSocketFactory;
@@ -1117,28 +981,19 @@
Landroid/net/SSLCertificateSocketFactory;->setChannelIdPrivateKey(Ljava/security/PrivateKey;)V
Landroid/net/SSLCertificateSocketFactory;->setSoWriteTimeout(Ljava/net/Socket;I)V
Landroid/net/SSLCertificateSocketFactory;->TAG:Ljava/lang/String;
-Landroid/net/SSLCertificateSocketFactory;->toLengthPrefixedList([[[B)[B
Landroid/net/SSLCertificateSocketFactory;->verifyHostname(Ljava/net/Socket;Ljava/lang/String;)V
Landroid/net/SSLSessionCache;->mSessionCache:Lcom/android/org/conscrypt/SSLClientSessionCache;
Landroid/net/TrafficStats;->getRxBytes(Ljava/lang/String;)J
Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService;
Landroid/net/TrafficStats;->getTxBytes(Ljava/lang/String;)J
-Landroid/net/TrafficStats;->setThreadStatsTagBackup()V
-Landroid/net/TrafficStats;->setThreadStatsTagRestore()V
-Landroid/net/TrafficStats;->setThreadStatsUid(I)V
Landroid/net/Uri;-><init>()V
-Landroid/net/WebAddress;-><init>(Ljava/lang/String;)V
Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiManager;
Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/WifiKey;-><init>(Ljava/lang/String;Ljava/lang/String;)V
Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V
Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
-Landroid/net/wifi/RttManager;->getRttCapabilities()Landroid/net/wifi/RttManager$RttCapabilities;
-Landroid/net/wifi/RttManager$RttParams;-><init>()V
-Landroid/net/wifi/RttManager;->startRanging([Landroid/net/wifi/RttManager$RttParams;Landroid/net/wifi/RttManager$RttListener;)V
Landroid/net/wifi/ScanResult;->anqpDomainId:I
Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List;
Landroid/net/wifi/ScanResult;->distanceCm:I
@@ -1151,54 +1006,22 @@
Landroid/net/wifi/ScanResult;->wifiSsid:Landroid/net/wifi/WifiSsid;
Landroid/net/wifi/WifiConfiguration;->apBand:I
Landroid/net/wifi/WifiConfiguration;->apChannel:I
-Landroid/net/wifi/WifiConfiguration;->creatorUid:I
-Landroid/net/wifi/WifiConfiguration;->hasNoInternetAccess()Z
-Landroid/net/wifi/WifiConfiguration;->isEphemeral()Z
-Landroid/net/wifi/WifiConfiguration;->isNoInternetAccessExpected()Z
-Landroid/net/wifi/WifiConfiguration;->lastUpdateUid:I
Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration;
-Landroid/net/wifi/WifiConfiguration;->numAssociation:I
Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z
Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
+Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String;
Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
-Landroid/net/wifi/WifiManager;->connect(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
-Landroid/net/wifi/WifiManager;->EXTRA_WIFI_AP_STATE:Ljava/lang/String;
Landroid/net/wifi/WifiManager;->forget(ILandroid/net/wifi/WifiManager$ActionListener;)V
-Landroid/net/wifi/WifiManager;->getPrivilegedConfiguredNetworks()Ljava/util/List;
-Landroid/net/wifi/WifiManager;->getWifiApConfiguration()Landroid/net/wifi/WifiConfiguration;
-Landroid/net/wifi/WifiManager;->getWifiApState()I
Landroid/net/wifi/WifiManager;->isDualBandSupported()Z
-Landroid/net/wifi/WifiManager;->isWifiApEnabled()Z
-Landroid/net/wifi/WifiManager;->isWifiScannerSupported()Z
Landroid/net/wifi/WifiManager;->mService:Landroid/net/wifi/IWifiManager;
Landroid/net/wifi/WifiManager;->save(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
-Landroid/net/wifi/WifiManager;->setWifiApConfiguration(Landroid/net/wifi/WifiConfiguration;)Z
-Landroid/net/wifi/WifiManager;->startScan(Landroid/os/WorkSource;)Z
-Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_CHANGED_ACTION:Ljava/lang/String;
-Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_DISABLED:I
-Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_DISABLING:I
-Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_ENABLED:I
-Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_ENABLING:I
-Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_FAILED:I
-Landroid/net/wifi/WifiScanner;->getScanResults()Z
-Landroid/net/wifi/WifiScanner$ScanData;->getResults()[Landroid/net/wifi/ScanResult;
-Landroid/net/wifi/WifiScanner$ScanSettings;-><init>()V
-Landroid/net/wifi/WifiScanner;->startBackgroundScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;)V
-Landroid/net/wifi/WifiScanner;->startScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;Landroid/os/WorkSource;)V
-Landroid/net/wifi/WifiScanner;->startScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;)V
-Landroid/net/wifi/WifiScanner;->stopBackgroundScan(Landroid/net/wifi/WifiScanner$ScanListener;)V
Landroid/net/wifi/WifiSsid;->NONE:Ljava/lang/String;
-Landroid/nfc/NfcAdapter;->addNfcUnlockHandler(Landroid/nfc/NfcAdapter$NfcUnlockHandler;[Ljava/lang/String;)Z
-Landroid/nfc/NfcAdapter;->disable()Z
-Landroid/nfc/NfcAdapter;->enable()Z
Landroid/nfc/NfcAdapter;->getDefaultAdapter()Landroid/nfc/NfcAdapter;
-Landroid/nfc/NfcAdapter;->removeNfcUnlockHandler(Landroid/nfc/NfcAdapter$NfcUnlockHandler;)Z
Landroid/nfc/NfcAdapter;->setNdefPushMessageCallback(Landroid/nfc/NfcAdapter$CreateNdefMessageCallback;Landroid/app/Activity;I)V
-Landroid/nfc/NfcAdapter;->setNdefPushMessage(Landroid/nfc/NdefMessage;Landroid/app/Activity;I)V
Landroid/opengl/GLSurfaceView$EglHelper;->mEglContext:Ljavax/microedition/khronos/egl/EGLContext;
Landroid/opengl/GLSurfaceView$GLThread;->mEglHelper:Landroid/opengl/GLSurfaceView$EglHelper;
Landroid/opengl/GLSurfaceView;->mGLThread:Landroid/opengl/GLSurfaceView$GLThread;
@@ -1227,7 +1050,6 @@
Landroid/os/Binder;->mObject:J
Landroid/os/Build;->getString(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/Build$VERSION;->ACTIVE_CODENAMES:[Ljava/lang/String;
-Landroid/os/Build$VERSION;->RESOURCES_SDK_INT:I
Landroid/os/Bundle;->getIBinder(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/Bundle;->putIBinder(Ljava/lang/String;Landroid/os/IBinder;)V
Landroid/os/Debug;->countInstancesOfClass(Ljava/lang/Class;)J
@@ -1262,6 +1084,7 @@
Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I
Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I
Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File;
+Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V
Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J
Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z
@@ -1277,8 +1100,8 @@
Landroid/os/Handler;->hasCallbacks(Ljava/lang/Runnable;)Z
Landroid/os/Handler;->mCallback:Landroid/os/Handler$Callback;
Landroid/os/Handler;->mMessenger:Landroid/os/IMessenger;
-Landroid/os/HwBlob;-><init>(I)V
Landroid/os/HwParcel;-><init>(Z)V
+Landroid/os/HwRemoteBinder;-><init>()V
Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/IPermissionController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPermissionController;
Landroid/os/IPermissionController$Stub$Proxy;->checkPermission(Ljava/lang/String;II)Z
@@ -1308,12 +1131,13 @@
Landroid/os/Message;->when:J
Landroid/os/ParcelFileDescriptor;-><init>(Ljava/io/FileDescriptor;)V
Landroid/os/Parcel;->mNativePtr:J
+Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
Landroid/os/Parcel$ReadWriteHelper;-><init>()V
+Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
-Landroid/os/PowerManager;->userActivity(JII)V
Landroid/os/PowerManager;->userActivity(JZ)V
Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
Landroid/os/PowerManager;->wakeUp(JLjava/lang/String;)V
@@ -1325,12 +1149,6 @@
Landroid/os/Process;->isIsolated(I)Z
Landroid/os/Process;->readProcFile(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z
Landroid/os/Process;->readProcLines(Ljava/lang/String;[Ljava/lang/String;[J)V
-Landroid/os/RecoverySystem;->cancelScheduledUpdate(Landroid/content/Context;)V
-Landroid/os/RecoverySystem;->installPackage(Landroid/content/Context;Ljava/io/File;Z)V
-Landroid/os/RecoverySystem;->processPackage(Landroid/content/Context;Ljava/io/File;Landroid/os/RecoverySystem$ProgressListener;Landroid/os/Handler;)V
-Landroid/os/RecoverySystem;->processPackage(Landroid/content/Context;Ljava/io/File;Landroid/os/RecoverySystem$ProgressListener;)V
-Landroid/os/RecoverySystem;->rebootWipeAb(Landroid/content/Context;Ljava/io/File;Ljava/lang/String;)V
-Landroid/os/RecoverySystem;->scheduleUpdateOnBoot(Landroid/content/Context;Ljava/io/File;)V
Landroid/os/SELinux;->isSELinuxEnabled()Z
Landroid/os/SELinux;->isSELinuxEnforced()Z
Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
@@ -1342,6 +1160,7 @@
Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap;
Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
+Landroid/os/SharedMemory;->getFd()I
Landroid/os/storage/DiskInfo;->getDescription()Ljava/lang/String;
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -1370,13 +1189,9 @@
Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V
Landroid/os/StrictMode;->getThreadPolicyMask()I
Landroid/os/StrictMode;->onBinderStrictModePolicyChange(I)V
+Landroid/os/StrictMode$ThreadPolicy$Builder;->penaltyListener(Landroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)Landroid/os/StrictMode$ThreadPolicy$Builder;
Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
Landroid/os/SystemProperties;->addChangeCallback(Ljava/lang/Runnable;)V
-Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z
-Landroid/os/SystemProperties;->getInt(Ljava/lang/String;I)I
-Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SystemProperties;->getLong(Ljava/lang/String;J)J
Landroid/os/SystemProperties;-><init>()V
Landroid/os/SystemProperties;->native_get(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/SystemProperties;->PROP_NAME_MAX:I
@@ -1390,15 +1205,6 @@
Landroid/os/Trace;->traceEnd(J)V
Landroid/os/Trace;->TRACE_TAG_APP:J
Landroid/os/Trace;->TRACE_TAG_VIEW:J
-Landroid/os/UpdateEngine;->applyPayload(Ljava/lang/String;JJ[Ljava/lang/String;)V
-Landroid/os/UpdateEngine;->bind(Landroid/os/UpdateEngineCallback;Landroid/os/Handler;)Z
-Landroid/os/UpdateEngine;->bind(Landroid/os/UpdateEngineCallback;)Z
-Landroid/os/UpdateEngineCallback;-><init>()V
-Landroid/os/UpdateEngineCallback;->onPayloadApplicationComplete(I)V
-Landroid/os/UpdateEngineCallback;->onStatusUpdate(IF)V
-Landroid/os/UpdateEngine;->cancel()V
-Landroid/os/UpdateEngine;-><init>()V
-Landroid/os/UpdateEngine;->resetStatus()V
Landroid/os/UpdateLock;->acquire()V
Landroid/os/UpdateLock;->isHeld()Z
Landroid/os/UpdateLock;->NOW_IS_CONVENIENT:Ljava/lang/String;
@@ -1408,13 +1214,9 @@
Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle;
Landroid/os/UserHandle;->getAppIdFromSharedAppGid(I)I
Landroid/os/UserHandle;->getCallingUserId()I
-Landroid/os/UserHandle;->getIdentifier()I
Landroid/os/UserHandle;->getUid(II)I
Landroid/os/UserHandle;->getUserId(I)I
Landroid/os/UserHandle;-><init>(I)V
-Landroid/os/UserHandle;->isOwner()Z
-Landroid/os/UserHandle;->myUserId()I
-Landroid/os/UserHandle;->of(I)Landroid/os/UserHandle;
Landroid/os/UserHandle;->PER_USER_RANGE:I
Landroid/os/UserHandle;->USER_OWNER:I
Landroid/os/UserManager;->getBadgedLabelForUser(Ljava/lang/CharSequence;Landroid/os/UserHandle;)Ljava/lang/CharSequence;
@@ -1423,25 +1225,25 @@
Landroid/os/UserManager;->getProfiles(I)Ljava/util/List;
Landroid/os/UserManager;->getUserHandle()I
Landroid/os/UserManager;->getUserHandle(I)I
+Landroid/os/UserManager;->getUserIcon(I)Landroid/graphics/Bitmap;
Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
-Landroid/os/UserManager;->getUserRestrictionSource(Ljava/lang/String;Landroid/os/UserHandle;)I
Landroid/os/UserManager;->getUserSerialNumber(I)I
Landroid/os/UserManager;->getUsers()Ljava/util/List;
Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
Landroid/os/UserManager;->isLinkedUser()Z
-Landroid/os/UserManager;->isManagedProfile()Z
Landroid/os/UserManager;->isUserUnlocked(I)Z
Landroid/os/VintfObject;->report()[Ljava/lang/String;
Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
Landroid/os/WorkSource;->add(I)Z
-Landroid/os/WorkSource;->createWorkChain()Landroid/os/WorkSource$WorkChain;
+Landroid/os/WorkSource;->addReturningNewbs(Landroid/os/WorkSource;)Landroid/os/WorkSource;
Landroid/os/WorkSource;->get(I)I
Landroid/os/WorkSource;->getName(I)Ljava/lang/String;
+Landroid/os/WorkSource;-><init>(I)V
Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
Landroid/os/WorkSource;->mNum:I
Landroid/os/WorkSource;->mUids:[I
+Landroid/os/WorkSource;->setReturningDiffs(Landroid/os/WorkSource;)[Landroid/os/WorkSource;
Landroid/os/WorkSource;->size()I
-Landroid/os/WorkSource$WorkChain;->addNode(ILjava/lang/String;)Landroid/os/WorkSource$WorkChain;
Landroid/preference/DialogPreference;->mBuilder:Landroid/app/AlertDialog$Builder;
Landroid/preference/DialogPreference;->mDialogIcon:Landroid/graphics/drawable/Drawable;
Landroid/preference/DialogPreference;->mDialog:Landroid/app/Dialog;
@@ -1487,20 +1289,17 @@
Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V
Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
Landroid/provider/Settings$Global;->ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED:Ljava/lang/String;
-Landroid/provider/Settings$Global;->OTA_DISABLE_AUTOMATIC_UPDATE:Ljava/lang/String;
Landroid/provider/Settings$Global;->PACKAGE_VERIFIER_ENABLE:Ljava/lang/String;
Landroid/provider/Settings$Global;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:Ljava/lang/String;
-Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_LARGE_POINTER_ICON:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ENABLED_NOTIFICATION_LISTENERS:Ljava/lang/String;
Landroid/provider/Settings$Secure;->INCALL_POWER_BUTTON_BEHAVIOR:Ljava/lang/String;
Landroid/provider/Settings$Secure;->LONG_PRESS_TIMEOUT:Ljava/lang/String;
Landroid/provider/Settings$Secure;->PACKAGE_VERIFIER_USER_CONSENT:Ljava/lang/String;
Landroid/provider/Settings$Secure;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
-Landroid/provider/Settings$Secure;->USER_SETUP_COMPLETE:Ljava/lang/String;
Landroid/provider/Settings$System;->AIRPLANE_MODE_TOGGLEABLE_RADIOS:Ljava/lang/String;
Landroid/provider/Settings$System;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String;
Landroid/provider/Settings$System;->HEARING_AID:Ljava/lang/String;
@@ -1709,11 +1508,43 @@
Landroid/R$styleable;->Window_windowBackground:I
Landroid/R$styleable;->Window_windowFrame:I
Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
+Landroid/security/keystore/KeychainProtectionParams;->clearSecret()V
+Landroid/security/keystore/KeychainProtectionParams;->getKeyDerivationParams()Landroid/security/keystore/KeyDerivationParams;
+Landroid/security/keystore/KeychainProtectionParams;->getLockScreenUiFormat()I
+Landroid/security/keystore/KeychainProtectionParams;->getSecret()[B
+Landroid/security/keystore/KeychainProtectionParams;->getUserSecretType()I
+Landroid/security/keystore/KeychainProtectionParams;-><init>(IILandroid/security/keystore/KeyDerivationParams;[B)V
+Landroid/security/keystore/KeychainProtectionParams;-><init>(Landroid/os/Parcel;)V
+Landroid/security/keystore/KeychainProtectionParams;-><init>()V
+Landroid/security/keystore/KeychainSnapshot;->getCounterId()J
+Landroid/security/keystore/KeychainSnapshot;->getEncryptedRecoveryKeyBlob()[B
+Landroid/security/keystore/KeychainSnapshot;->getKeychainProtectionParams()Ljava/util/List;
+Landroid/security/keystore/KeychainSnapshot;->getMaxAttempts()I
+Landroid/security/keystore/KeychainSnapshot;->getServerParams()[B
+Landroid/security/keystore/KeychainSnapshot;->getSnapshotVersion()I
+Landroid/security/keystore/KeychainSnapshot;->getTrustedHardwarePublicKey()[B
+Landroid/security/keystore/KeychainSnapshot;->getWrappedApplicationKeys()Ljava/util/List;
+Landroid/security/keystore/KeyDerivationParams;->ALGORITHM_ARGON2ID:I
+Landroid/security/keystore/KeyDerivationParams;->ALGORITHM_SHA256:I
+Landroid/security/keystore/KeyDerivationParams;->createSha256Params([B)Landroid/security/keystore/KeyDerivationParams;
+Landroid/security/keystore/KeyDerivationParams;->getAlgorithm()I
+Landroid/security/keystore/KeyDerivationParams;->getSalt()[B
+Landroid/security/keystore/KeyDerivationParams;-><init>(I[B)V
+Landroid/security/keystore/KeyDerivationParams;-><init>(Landroid/os/Parcel;)V
+Landroid/security/keystore/RecoveryClaim;->getClaimBytes()[B
+Landroid/security/keystore/RecoveryClaim;->getRecoverySession()Landroid/security/keystore/RecoverySession;
Landroid/security/keystore/RecoveryController;->getInstance()Landroid/security/keystore/RecoveryController;
+Landroid/security/keystore/RecoveryController;->getRecoveryData([B)Landroid/security/keystore/KeychainSnapshot;
Landroid/security/keystore/RecoveryController;->initRecoveryService(Ljava/lang/String;[B)V
+Landroid/security/keystore/RecoveryController;->recoverKeys(Landroid/security/keystore/RecoverySession;[BLjava/util/List;)Ljava/util/Map;
Landroid/security/keystore/RecoveryController;->setRecoverySecretTypes([I)V
+Landroid/security/keystore/RecoveryController;->setRecoveryStatus(Ljava/lang/String;[Ljava/lang/String;I)V
Landroid/security/keystore/RecoveryController;->setServerParams([B)V
Landroid/security/keystore/RecoveryController;->setSnapshotCreatedPendingIntent(Landroid/app/PendingIntent;)V
+Landroid/security/keystore/RecoveryController;->startRecoverySession([B[B[BLjava/util/List;)Landroid/security/keystore/RecoveryClaim;
+Landroid/security/keystore/WrappedApplicationKey;->getAlias()Ljava/lang/String;
+Landroid/security/keystore/WrappedApplicationKey;->getEncryptedKeyMaterial()[B
+Landroid/security/keystore/WrappedApplicationKey;-><init>(Ljava/lang/String;[B)V
Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnectFailed()V
Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnect(Ljava/lang/String;Landroid/media/session/MediaSession$Token;Landroid/os/Bundle;)V
@@ -1724,38 +1555,11 @@
Landroid/service/media/MediaBrowserService$Result;->mFlags:I
Landroid/service/notification/NotificationListenerService;->registerAsSystemService(Landroid/content/Context;Landroid/content/ComponentName;I)V
Landroid/service/notification/NotificationListenerService;->unregisterAsSystemService()V
-Landroid/service/persistentdata/PersistentDataBlockManager;->getFlashLockState()I
-Landroid/service/persistentdata/PersistentDataBlockManager;->getMaximumDataBlockSize()J
-Landroid/service/persistentdata/PersistentDataBlockManager;->read()[B
-Landroid/service/persistentdata/PersistentDataBlockManager;->write([B)I
-Landroid/service/resolver/ResolverRankerService;-><init>()V
-Landroid/service/resolver/ResolverTarget;->getChooserScore()F
-Landroid/service/resolver/ResolverTarget;->getLaunchScore()F
-Landroid/service/resolver/ResolverTarget;->getRecencyScore()F
-Landroid/service/resolver/ResolverTarget;->getSelectProbability()F
-Landroid/service/resolver/ResolverTarget;->getTimeSpentScore()F
-Landroid/service/resolver/ResolverTarget;->setSelectProbability(F)V
-Landroid/service/trust/TrustAgentService;-><init>()V
Landroid/service/voice/VoiceInteractionService;->isKeyphraseAndLocaleSupportedForHotword(Ljava/lang/String;Ljava/util/Locale;)Z
Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
Landroid/system/Int32Ref;->value:I
Landroid/system/StructTimeval;->fromMillis(J)Landroid/system/StructTimeval;
-Landroid/telecom/AudioState;->getRoute()I
-Landroid/telecom/AudioState;->getSupportedRouteMask()I
-Landroid/telecom/AudioState;->isMuted()Z
-Landroid/telecom/Call;->addListener(Landroid/telecom/Call$Listener;)V
-Landroid/telecom/Call$Listener;-><init>()V
-Landroid/telecom/Call;->removeListener(Landroid/telecom/Call$Listener;)V
-Landroid/telecom/Phone;->addListener(Landroid/telecom/Phone$Listener;)V
-Landroid/telecom/Phone;->getAudioState()Landroid/telecom/AudioState;
-Landroid/telecom/Phone;->getCallAudioState()Landroid/telecom/CallAudioState;
-Landroid/telecom/Phone;->getCalls()Ljava/util/List;
-Landroid/telecom/Phone$Listener;-><init>()V
-Landroid/telecom/Phone;->removeListener(Landroid/telecom/Phone$Listener;)V
-Landroid/telecom/Phone;->setAudioRoute(I)V
-Landroid/telecom/Phone;->setMuted(Z)V
-Landroid/telecom/TelecomManager;->endCall()Z
Landroid/telecom/TelecomManager;->EXTRA_IS_HANDOVER:Ljava/lang/String;
Landroid/telecom/TelecomManager;->getUserSelectedOutgoingPhoneAccount()Landroid/telecom/PhoneAccountHandle;
Landroid/telecom/TelecomManager;->setUserSelectedOutgoingPhoneAccount(Landroid/telecom/PhoneAccountHandle;)V
@@ -1788,24 +1592,19 @@
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_MODERATE:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_NONE_OR_UNKNOWN:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_POOR:I
-Landroid/telephony/SmsManager;->RESULT_ERROR_FDN_CHECK_FAILURE:I
Landroid/telephony/SmsMessage;->getSubId()I
Landroid/telephony/SmsMessage;->mWrappedSmsMessage:Lcom/android/internal/telephony/SmsMessageBase;
Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I
+Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoList()Ljava/util/List;
Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I
+Landroid/telephony/SubscriptionManager;->getDefaultVoiceSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
Landroid/telephony/SubscriptionManager;->getSlotIndex(I)I
Landroid/telephony/SubscriptionManager;->getSubId(I)[I
Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
-Landroid/telephony/TelephonyManager;->checkCarrierPrivilegesForPackage(Ljava/lang/String;)I
Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
Landroid/telephony/TelephonyManager;->getCallState(I)I
-Landroid/telephony/TelephonyManager;->getCarrierPackageNamesForIntent(Landroid/content/Intent;)Ljava/util/List;
-Landroid/telephony/TelephonyManager;->getCurrentPhoneType()I
-Landroid/telephony/TelephonyManager;->getCurrentPhoneType(I)I
-Landroid/telephony/TelephonyManager;->getDataEnabled(I)Z
-Landroid/telephony/TelephonyManager;->getDataEnabled()Z
Landroid/telephony/TelephonyManager;->getDataNetworkType(I)I
Landroid/telephony/TelephonyManager;->getDefault()Landroid/telephony/TelephonyManager;
Landroid/telephony/TelephonyManager;->getGroupIdLevel1(I)Ljava/lang/String;
@@ -1836,7 +1635,6 @@
Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z
Landroid/telephony/TelephonyManager;->isVolteAvailable()Z
-Landroid/telephony/TelephonyManager;->setDataEnabled(IZ)V
Landroid/text/AndroidBidi;->bidi(I[C[B)I
Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V
Landroid/text/DynamicLayout;->sStaticLayout:Landroid/text/StaticLayout;
@@ -1900,6 +1698,8 @@
Landroid/text/TextPaint;->setUnderlineText(IF)V
Landroid/transition/ChangeBounds;->BOTTOM_RIGHT_ONLY_PROPERTY:Landroid/util/Property;
Landroid/transition/ChangeBounds;->POSITION_PROPERTY:Landroid/util/Property;
+Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal;
+Landroid/util/ArrayMap;->append(Ljava/lang/Object;Ljava/lang/Object;)V
Landroid/util/ArrayMap;->mBaseCacheSize:I
Landroid/util/ArrayMap;->mTwiceBaseCacheSize:I
Landroid/util/DisplayMetrics;->noncompatHeightPixels:I
@@ -1915,6 +1715,8 @@
Landroid/util/NtpTrustedTime;->getInstance(Landroid/content/Context;)Landroid/util/NtpTrustedTime;
Landroid/util/NtpTrustedTime;->hasCache()Z
Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Rational;->mDenominator:I
+Landroid/util/Rational;->mNumerator:I
Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
Landroid/util/SparseIntArray;->mKeys:[I
@@ -1927,10 +1729,10 @@
Landroid/view/accessibility/AccessibilityManager;->sInstance:Landroid/view/accessibility/AccessibilityManager;
Landroid/view/accessibility/AccessibilityManager;->sInstanceSync:Ljava/lang/Object;
Landroid/view/accessibility/AccessibilityNodeInfo;->refresh(Landroid/os/Bundle;Z)Z
+Landroid/view/accessibility/AccessibilityRecord;->getSourceNodeId()J
Landroid/view/accessibility/IAccessibilityManager;->getEnabledAccessibilityServiceList(II)Ljava/util/List;
Landroid/view/accessibility/IAccessibilityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/accessibility/IAccessibilityManager;
Landroid/view/accessibility/IAccessibilityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/view/ActionMode;->isUiFocusable()Z
Landroid/view/animation/Animation;->mListener:Landroid/view/animation/Animation$AnimationListener;
Landroid/view/autofill/IAutoFillManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/Choreographer$CallbackQueue;->addCallbackLocked(JLjava/lang/Object;Ljava/lang/Object;)V
@@ -1939,8 +1741,6 @@
Landroid/view/Choreographer;->mCallbackQueues:[Landroid/view/Choreographer$CallbackQueue;
Landroid/view/Choreographer;->mLastFrameTimeNanos:J
Landroid/view/Choreographer;->mLock:Ljava/lang/Object;
-Landroid/view/Choreographer;->postCallback(ILjava/lang/Runnable;Ljava/lang/Object;)V
-Landroid/view/Choreographer;->removeCallbacks(ILjava/lang/Runnable;Ljava/lang/Object;)V
Landroid/view/Choreographer;->scheduleVsyncLocked()V
Landroid/view/Choreographer;->USE_VSYNC:Z
Landroid/view/ContextThemeWrapper;->getThemeResId()I
@@ -2194,89 +1994,28 @@
Landroid/view/WindowManager$LayoutParams;->hideTimeoutMilliseconds:J
Landroid/view/WindowManager$LayoutParams;->needsMenuKey:I
Landroid/view/WindowManager$LayoutParams;->NEEDS_MENU_SET_TRUE:I
-Landroid/view/WindowManager$LayoutParams;->PRIVATE_FLAG_NO_MOVE_ANIMATION:I
-Landroid/view/WindowManager$LayoutParams;->privateFlags:I
Landroid/view/WindowManager$LayoutParams;->userActivityTimeout:J
Landroid/view/Window;->mAppName:Ljava/lang/String;
Landroid/view/Window;->mAppToken:Landroid/os/IBinder;
Landroid/view/Window;->mHardwareAccelerated:Z
-Landroid/webkit/FindActionModeCallback;->findAll()V
-Landroid/webkit/FindActionModeCallback;-><init>(Landroid/content/Context;)V
-Landroid/webkit/FindActionModeCallback;->setText(Ljava/lang/String;)V
-Landroid/webkit/FindActionModeCallback;->setWebView(Landroid/webkit/WebView;)V
-Landroid/webkit/FindActionModeCallback;->showSoftInput()V
-Landroid/webkit/GeolocationPermissions;-><init>()V
-Landroid/webkit/HttpAuthHandler;-><init>()V
Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/webkit/JsDialogHelper;-><init>(Landroid/webkit/JsPromptResult;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Landroid/webkit/JsDialogHelper;->showDialog(Landroid/content/Context;)V
-Landroid/webkit/JsPromptResult;->getStringResult()Ljava/lang/String;
-Landroid/webkit/JsPromptResult;-><init>(Landroid/webkit/JsResult$ResultReceiver;)V
-Landroid/webkit/SslErrorHandler;-><init>()V
-Landroid/webkit/TokenBindingService;-><init>()V
-Landroid/webkit/TokenBindingService$TokenBindingKey;-><init>()V
-Landroid/webkit/WebChromeClient;->openFileChooser(Landroid/webkit/ValueCallback;Ljava/lang/String;Ljava/lang/String;)V
-Landroid/webkit/WebMessagePort;-><init>()V
-Landroid/webkit/WebResourceError;-><init>()V
-Landroid/webkit/WebResourceResponse;-><init>(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;Ljava/io/InputStream;)V
Landroid/webkit/WebResourceResponse;->mImmutable:Z
-Landroid/webkit/WebSettings;->getAcceptThirdPartyCookies()Z
-Landroid/webkit/WebSettings;->setAcceptThirdPartyCookies(Z)V
-Landroid/webkit/WebSettings;->setNavDump(Z)V
-Landroid/webkit/WebSettings;->setPluginsEnabled(Z)V
-Landroid/webkit/WebStorage;-><init>()V
-Landroid/webkit/WebStorage$Origin;-><init>(Ljava/lang/String;JJ)V
Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler;
Landroid/webkit/WebView;->debugDump()V
-Landroid/webkit/WebViewDelegate;->addWebViewAssetPath(Landroid/content/Context;)V
-Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;JLjava/lang/Runnable;)V
-Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;J)V
-Landroid/webkit/WebViewDelegate;->canInvokeDrawGlFunctor(Landroid/view/View;)Z
-Landroid/webkit/WebViewDelegate;->detachDrawGlFunctor(Landroid/view/View;J)V
-Landroid/webkit/WebViewDelegate;->getApplication()Landroid/app/Application;
-Landroid/webkit/WebViewDelegate;->getDataDirectorySuffix()Ljava/lang/String;
-Landroid/webkit/WebViewDelegate;->getErrorString(Landroid/content/Context;I)Ljava/lang/String;
-Landroid/webkit/WebViewDelegate;->getPackageId(Landroid/content/res/Resources;Ljava/lang/String;)I
-Landroid/webkit/WebViewDelegate;->invokeDrawGlFunctor(Landroid/view/View;JZ)V
-Landroid/webkit/WebViewDelegate;->isMultiProcessEnabled()Z
-Landroid/webkit/WebViewDelegate;->isTraceTagEnabled()Z
-Landroid/webkit/WebViewDelegate;->setOnTraceEnabledChangeListener(Landroid/webkit/WebViewDelegate$OnTraceEnabledChangeListener;)V
Landroid/webkit/WebView;->disablePlatformNotifications()V
Landroid/webkit/WebView;->emulateShiftHeld()V
Landroid/webkit/WebView;->enablePlatformNotifications()V
-Landroid/webkit/WebViewFactory;->getLoadedPackageInfo()Landroid/content/pm/PackageInfo;
Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
Landroid/webkit/WebViewFactory;->getWebViewContextAndSetProvider()Landroid/content/Context;
-Landroid/webkit/WebViewFactory;->loadWebViewNativeLibraryFromPackage(Ljava/lang/String;Ljava/lang/ClassLoader;)I
-Landroid/webkit/WebViewFactoryProvider;->getStatics()Landroid/webkit/WebViewFactoryProvider$Statics;
-Landroid/webkit/WebViewFactoryProvider$Statics;->getDefaultUserAgent(Landroid/content/Context;)Ljava/lang/String;
Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
Landroid/webkit/WebViewFactory;->sProviderInstance:Landroid/webkit/WebViewFactoryProvider;
Landroid/webkit/WebView;->getVisibleTitleHeight()I
-Landroid/webkit/WebView;->getWebViewProvider()Landroid/webkit/WebViewProvider;
-Landroid/webkit/WebView$HitTestResult;-><init>()V
-Landroid/webkit/WebView$HitTestResult;->setExtra(Ljava/lang/String;)V
-Landroid/webkit/WebView$HitTestResult;->setType(I)V
Landroid/webkit/WebView;->isPaused()Z
Landroid/webkit/WebView;->mProvider:Landroid/webkit/WebViewProvider;
Landroid/webkit/WebView;->notifyFindDialogDismissed()V
-Landroid/webkit/WebView$PrivateAccess;->overScrollBy(IIIIIIIIZ)V
-Landroid/webkit/WebView$PrivateAccess;->setMeasuredDimension(II)V
-Landroid/webkit/WebView$PrivateAccess;->super_dispatchKeyEvent(Landroid/view/KeyEvent;)Z
-Landroid/webkit/WebView$PrivateAccess;->super_getScrollBarStyle()I
-Landroid/webkit/WebView$PrivateAccess;->super_onDrawVerticalScrollBar(Landroid/graphics/Canvas;Landroid/graphics/drawable/Drawable;IIII)V
-Landroid/webkit/WebView$PrivateAccess;->super_onGenericMotionEvent(Landroid/view/MotionEvent;)Z
-Landroid/webkit/WebView$PrivateAccess;->super_performAccessibilityAction(ILandroid/os/Bundle;)Z
-Landroid/webkit/WebView$PrivateAccess;->super_performLongClick()Z
-Landroid/webkit/WebView$PrivateAccess;->super_requestFocus(ILandroid/graphics/Rect;)Z
-Landroid/webkit/WebView$PrivateAccess;->super_scrollTo(II)V
-Landroid/webkit/WebView$PrivateAccess;->super_setFrame(IIII)Z
-Landroid/webkit/WebView$PrivateAccess;->super_setLayoutParams(Landroid/view/ViewGroup$LayoutParams;)V
-Landroid/webkit/WebView$PrivateAccess;->super_startActivityForResult(Landroid/content/Intent;I)V
Landroid/webkit/WebView;->restorePicture(Landroid/os/Bundle;Ljava/io/File;)Z
Landroid/webkit/WebView;->savePicture(Landroid/os/Bundle;Ljava/io/File;)Z
Landroid/webkit/WebView;->sEnforceThreadChecking:Z
-Landroid/webkit/WebViewUpdateService;->getCurrentWebViewPackageName()Ljava/lang/String;
Landroid/widget/AbsListView$FlingRunnable;->endFling()V
Landroid/widget/AbsListView$FlingRunnable;->mScroller:Landroid/widget/OverScroller;
Landroid/widget/AbsListView$FlingRunnable;->start(I)V
@@ -2473,6 +2212,73 @@
Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
Landroid/widget/VideoView;->mVideoHeight:I
Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/ims/internal/uce/common/CapInfo;-><init>()V
+Lcom/android/ims/internal/uce/common/CapInfo;->setCapTimestamp(J)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setCdViaPresenceSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setExts([Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtHttpSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtSnFSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtThumbSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFullSnFGroupChatSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullFtSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPushSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setImSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIpVideoSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIpVoiceSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIsSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoOnlyCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVoiceCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setSmSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setSpSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setVsDuringCSSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setVsSupported(Z)V
+Lcom/android/ims/internal/uce/common/StatusCode;-><init>()V
+Lcom/android/ims/internal/uce/common/StatusCode;->setStatusCode(I)V
+Lcom/android/ims/internal/uce/common/UceLong;->getUceLong()J
+Lcom/android/ims/internal/uce/common/UceLong;->setUceLong(J)V
+Lcom/android/ims/internal/uce/presence/PresCmdId;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresCmdId;->setCmdId(I)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setStatus(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setUserData(I)V
+Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;->setPublishTrigeerType(I)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setDisplayName(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setInstanceInfo(Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setResUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setPresentityUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setReason(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResId(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResInstanceState(I)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setTupleInfo([Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setFullState(Z)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setListName(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setPresSubscriptionState(Lcom/android/ims/internal/uce/presence/PresSubscriptionState;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionExpireTime(I)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionTerminatedReason(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setVersion(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setReasonPhrase(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRetryAfter(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setSipResponseCode(I)V
+Lcom/android/ims/internal/uce/presence/PresSubscriptionState;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresSubscriptionState;->setPresSubscriptionState(I)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;-><init>()V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setContactUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setFeatureTag(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setTimestamp(Ljava/lang/String;)V
Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -2481,6 +2287,7 @@
Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService;
Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
+Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
Lcom/android/internal/os/BatterySipper;->add(Lcom/android/internal/os/BatterySipper;)V
Lcom/android/internal/os/BatterySipper;->drainType:Lcom/android/internal/os/BatterySipper$DrainType;
Lcom/android/internal/os/BatterySipper;->getUid()I
@@ -2676,6 +2483,7 @@
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/util/FastPrintWriter;-><init>(Ljava/io/OutputStream;)V
Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap;
Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List;
@@ -2741,6 +2549,7 @@
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J
Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
+Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy;
@@ -2750,6 +2559,7 @@
Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
Ldalvik/system/CloseGuard;->warnIfOpen()V
Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
+Ldalvik/system/DexFile;->isBackedByOatFile()Z
Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
@@ -2870,6 +2680,7 @@
Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->nativeFillInStackTrace()Ljava/lang/Object;
Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
@@ -2939,6 +2750,7 @@
Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormat;->is24Hour:Ljava/lang/Boolean;
Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
@@ -2961,11 +2773,13 @@
Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Duration;->toSeconds()Ljava/math/BigDecimal;
Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetDateTime;-><init>(Ljava/time/LocalDateTime;Ljava/time/ZoneOffset;)V
Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
@@ -3072,6 +2886,7 @@
Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Random;->seedUniquifier()J
Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/regex/Matcher;->appendPos:I
Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 99c5d2b..5687780 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -995,9 +995,9 @@
* cursors for data being displayed, etc.
*
* <p>You can call {@link #finish} from within this function, in
- * which case onDestroy() will be immediately called without any of the rest
- * of the activity lifecycle ({@link #onStart}, {@link #onResume},
- * {@link #onPause}, etc) executing.
+ * which case onDestroy() will be immediately called after {@link #onCreate} without any of the
+ * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc)
+ * executing.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2d73ce0..a18ba71 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2101,15 +2101,17 @@
private final int mOrientation;
private final Rect mContentInsets;
private final boolean mReducedResolution;
+ private final boolean mIsRealSnapshot;
private final float mScale;
public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets,
- boolean reducedResolution, float scale) {
+ boolean reducedResolution, float scale, boolean isRealSnapshot) {
mSnapshot = snapshot;
mOrientation = orientation;
mContentInsets = new Rect(contentInsets);
mReducedResolution = reducedResolution;
mScale = scale;
+ mIsRealSnapshot = isRealSnapshot;
}
private TaskSnapshot(Parcel source) {
@@ -2118,6 +2120,7 @@
mContentInsets = source.readParcelable(null /* classLoader */);
mReducedResolution = source.readBoolean();
mScale = source.readFloat();
+ mIsRealSnapshot = source.readBoolean();
}
/**
@@ -2150,6 +2153,14 @@
}
/**
+ * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot
+ * due to the task having a secure window or having previews disabled.
+ */
+ public boolean isRealSnapshot() {
+ return mIsRealSnapshot;
+ }
+
+ /**
* @return The scale this snapshot was taken in.
*/
public float getScale() {
@@ -2168,13 +2179,15 @@
dest.writeParcelable(mContentInsets, 0);
dest.writeBoolean(mReducedResolution);
dest.writeFloat(mScale);
+ dest.writeBoolean(mIsRealSnapshot);
}
@Override
public String toString() {
return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation
+ " mContentInsets=" + mContentInsets.toShortString()
- + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale;
+ + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale
+ + " mIsRealSnapshot=" + mIsRealSnapshot;
}
public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c78255f..cab6744 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -27,6 +27,7 @@
import android.os.SystemClock;
import android.service.voice.IVoiceInteractionSession;
import android.util.SparseIntArray;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
@@ -264,6 +265,17 @@
public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi);
/**
+ * Sets if the given pid is currently running a remote animation, which is taken a signal for
+ * determining oom adjustment and scheduling behavior.
+ *
+ * @param pid The pid we are setting overlay UI for.
+ * @param runningRemoteAnimation True if the process is running a remote animation, false
+ * otherwise.
+ * @see RemoteAnimationAdapter
+ */
+ public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation);
+
+ /**
* Called after the network policy rules are updated by
* {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and
* {@param procStateSeq}.
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 81cbbca..41eeb9a 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -191,6 +191,16 @@
}
}
+ /**
+ * Returns the name of the current process. A package's default process name
+ * is the same as its package name. Non-default processes will look like
+ * "$PACKAGE_NAME:$NAME", where $NAME corresponds to an android:process
+ * attribute within AndroidManifest.xml.
+ */
+ public static String getProcessName() {
+ return ActivityThread.currentProcessName();
+ }
+
// ------------------ Internal API ------------------
/**
@@ -333,4 +343,4 @@
}
return null;
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b207d57..46d1264 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1072,20 +1072,77 @@
* @hide
*/
public static final int SUPPRESSED_EFFECTS_UNSET = -1;
+
/**
* Whether notifications suppressed by DND should not interrupt visually (e.g. with
* notification lights or by turning the screen on) when the screen is off.
+ *
+ * @deprecated use {@link #SUPPRESSED_EFFECT_FULL_SCREEN_INTENT} and
+ * {@link #SUPPRESSED_EFFECT_AMBIENT} and {@link #SUPPRESSED_EFFECT_LIGHTS} individually.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
/**
* Whether notifications suppressed by DND should not interrupt visually when the screen
* is on (e.g. by peeking onto the screen).
+ *
+ * @deprecated use {@link #SUPPRESSED_EFFECT_PEEK}.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
+ /**
+ * Whether {@link Notification#fullScreenIntent full screen intents} from
+ * notifications intercepted by DND are blocked.
+ */
+ public static final int SUPPRESSED_EFFECT_FULL_SCREEN_INTENT = 1 << 2;
+
+ /**
+ * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
+ * notifications intercepted by DND are blocked.
+ */
+ public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 3;
+
+ /**
+ * Whether notifications intercepted by DND are prevented from peeking.
+ */
+ public static final int SUPPRESSED_EFFECT_PEEK = 1 << 4;
+
+ /**
+ * Whether notifications intercepted by DND are prevented from appearing in the status bar,
+ * on devices that support status bars.
+ */
+ public static final int SUPPRESSED_EFFECT_STATUS_BAR = 1 << 5;
+
+ /**
+ * Whether {@link NotificationChannel#canShowBadge() badges} from
+ * notifications intercepted by DND are blocked on devices that support badging.
+ */
+ public static final int SUPPRESSED_EFFECT_BADGE = 1 << 6;
+
+ /**
+ * Whether notification intercepted by DND are prevented from appearing on ambient displays
+ * on devices that support ambient display.
+ */
+ public static final int SUPPRESSED_EFFECT_AMBIENT = 1 << 7;
+
+ /**
+ * Whether notification intercepted by DND are prevented from appearing in notification
+ * list views like the notification shade or lockscreen on devices that support those
+ * views.
+ */
+ public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 1 << 8;
+
private static final int[] ALL_SUPPRESSED_EFFECTS = {
SUPPRESSED_EFFECT_SCREEN_OFF,
SUPPRESSED_EFFECT_SCREEN_ON,
+ SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+ SUPPRESSED_EFFECT_LIGHTS,
+ SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_STATUS_BAR,
+ SUPPRESSED_EFFECT_BADGE,
+ SUPPRESSED_EFFECT_AMBIENT,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST
};
/**
@@ -1097,6 +1154,12 @@
/**
* Constructs a policy for Do Not Disturb priority mode behavior.
*
+ * <p>
+ * Apps that target API levels below {@link Build.VERSION_CODES#P} cannot
+ * change user-designated values to allow or disallow
+ * {@link Policy#PRIORITY_CATEGORY_ALARMS}, {@link Policy#PRIORITY_CATEGORY_SYSTEM}, and
+ * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd.
+ *
* @param priorityCategories bitmask of categories of notifications that can bypass DND.
* @param priorityCallSenders which callers can bypass DND.
* @param priorityMessageSenders which message senders can bypass DND.
@@ -1109,6 +1172,26 @@
/**
* Constructs a policy for Do Not Disturb priority mode behavior.
*
+ * <p>
+ * Apps that target API levels below {@link Build.VERSION_CODES#P} cannot
+ * change user-designated values to allow or disallow
+ * {@link Policy#PRIORITY_CATEGORY_ALARMS}, {@link Policy#PRIORITY_CATEGORY_SYSTEM}, and
+ * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd.
+ * <p>
+ * Additionally, apps that target API levels below {@link Build.VERSION_CODES#P} can
+ * only modify the {@link #SUPPRESSED_EFFECT_SCREEN_ON} and
+ * {@link #SUPPRESSED_EFFECT_SCREEN_OFF} bits of the suppressed visual effects field.
+ * All other suppressed effects will be ignored and reconstituted from the screen on
+ * and screen off values.
+ * <p>
+ * Apps that target {@link Build.VERSION_CODES#P} or above can set any
+ * suppressed visual effects. However, if any suppressed effects >
+ * {@link #SUPPRESSED_EFFECT_SCREEN_ON} are set, {@link #SUPPRESSED_EFFECT_SCREEN_ON}
+ * and {@link #SUPPRESSED_EFFECT_SCREEN_OFF} will be ignored and reconstituted from
+ * the more specific suppressed visual effect bits. Apps should migrate to targeting
+ * specific effects instead of the deprecated {@link #SUPPRESSED_EFFECT_SCREEN_ON} and
+ * {@link #SUPPRESSED_EFFECT_SCREEN_OFF} effects.
+ *
* @param priorityCategories bitmask of categories of notifications that can bypass DND.
* @param priorityCallSenders which callers can bypass DND.
* @param priorityMessageSenders which message senders can bypass DND.
@@ -1190,6 +1273,30 @@
}
}
+ /**
+ * @hide
+ */
+ public static int getAllSuppressedVisualEffects() {
+ int effects = 0;
+ for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+ effects |= ALL_SUPPRESSED_EFFECTS[i];
+ }
+ return effects;
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean areAllVisualEffectsSuppressed(int effects) {
+ for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+ final int effect = ALL_SUPPRESSED_EFFECTS[i];
+ if ((effects & effect) == 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static String suppressedEffectsToString(int effects) {
if (effects <= 0) return "";
final StringBuilder sb = new StringBuilder();
@@ -1228,9 +1335,26 @@
private static String effectToString(int effect) {
switch (effect) {
- case SUPPRESSED_EFFECT_SCREEN_OFF: return "SUPPRESSED_EFFECT_SCREEN_OFF";
- case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
- case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
+ case SUPPRESSED_EFFECT_FULL_SCREEN_INTENT:
+ return "SUPPRESSED_EFFECT_FULL_SCREEN_INTENT";
+ case SUPPRESSED_EFFECT_LIGHTS:
+ return "SUPPRESSED_EFFECT_LIGHTS";
+ case SUPPRESSED_EFFECT_PEEK:
+ return "SUPPRESSED_EFFECT_PEEK";
+ case SUPPRESSED_EFFECT_STATUS_BAR:
+ return "SUPPRESSED_EFFECT_STATUS_BAR";
+ case SUPPRESSED_EFFECT_BADGE:
+ return "SUPPRESSED_EFFECT_BADGE";
+ case SUPPRESSED_EFFECT_AMBIENT:
+ return "SUPPRESSED_EFFECT_AMBIENT";
+ case SUPPRESSED_EFFECT_NOTIFICATION_LIST:
+ return "SUPPRESSED_EFFECT_NOTIFICATION_LIST";
+ case SUPPRESSED_EFFECT_SCREEN_OFF:
+ return "SUPPRESSED_EFFECT_SCREEN_OFF";
+ case SUPPRESSED_EFFECT_SCREEN_ON:
+ return "SUPPRESSED_EFFECT_SCREEN_ON";
+ case SUPPRESSED_EFFECTS_UNSET:
+ return "SUPPRESSED_EFFECTS_UNSET";
default: return "UNKNOWN_" + effect;
}
}
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index c2c91c2..b12e3bc 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -54,6 +54,12 @@
public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID =
"android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
/**
+ * List<String> of the relevant statsd_config.proto's BroadcastSubscriberDetails.cookie.
+ * Obtain using {@link android.content.Intent#getStringArrayListExtra(String)}.
+ */
+ public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES =
+ "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
+ /**
* Extra of a {@link android.os.StatsDimensionsValue} representing sliced dimension value
* information.
*/
@@ -146,7 +152,8 @@
* {@link #EXTRA_STATS_CONFIG_UID},
* {@link #EXTRA_STATS_CONFIG_KEY},
* {@link #EXTRA_STATS_SUBSCRIPTION_ID},
- * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and
+ * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID},
+ * {@link #EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES}, and
* {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
* <p>
* This function can only be called by the owner (uid) of the config. It must be called each
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index ef41b10..d568662 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2237,6 +2237,22 @@
return mWindowNodes.get(index);
}
+ // TODO(b/35708678): temporary method that disable one-way warning flag on binder.
+ /** @hide */
+ public void ensureDataForAutofill() {
+ if (mHaveData) {
+ return;
+ }
+ mHaveData = true;
+ Binder.allowBlocking(mReceiveChannel);
+ try {
+ ParcelTransferReader reader = new ParcelTransferReader(mReceiveChannel);
+ reader.go();
+ } finally {
+ Binder.defaultBlocking(mReceiveChannel);
+ }
+ }
+
/** @hide */
public void ensureData() {
if (mHaveData) {
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index 65e54f9..d6f2352 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -142,11 +142,8 @@
*/
public static final String HINT_SEE_MORE = "see_more";
/**
- * A hint used when implementing app-specific slice permissions.
- * Tells the system that for this slice the return value of
- * {@link SliceProvider#onBindSlice(Uri, List)} may be different depending on
- * {@link SliceProvider#getBindingPackage} and should not be cached for multiple
- * apps.
+ * @see Builder#setCallerNeeded
+ * @hide
*/
public static final String HINT_CALLER_NEEDED = "caller_needed";
/**
@@ -290,6 +287,14 @@
}
/**
+ * Returns whether the caller for this slice matters.
+ * @see Builder#setCallerNeeded
+ */
+ public boolean isCallerNeeded() {
+ return hasHint(HINT_CALLER_NEEDED);
+ }
+
+ /**
* A Builder used to construct {@link Slice}s
*/
public static class Builder {
@@ -318,6 +323,21 @@
}
/**
+ * Tells the system whether for this slice the return value of
+ * {@link SliceProvider#onBindSlice(Uri, List)} may be different depending on
+ * {@link SliceProvider#getCallingPackage()} and should not be cached for multiple
+ * apps.
+ */
+ public Builder setCallerNeeded(boolean callerNeeded) {
+ if (callerNeeded) {
+ mHints.add(HINT_CALLER_NEEDED);
+ } else {
+ mHints.remove(HINT_CALLER_NEEDED);
+ }
+ return this;
+ }
+
+ /**
* Add hints to the Slice being constructed
*/
public Builder addHints(@SliceHint String... hints) {
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index ae1d8d7..4f3cd63 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -16,9 +16,10 @@
package android.app.slice;
-import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -34,9 +35,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.util.ArrayMap;
import android.util.Log;
-import android.util.Pair;
import com.android.internal.util.Preconditions;
@@ -45,7 +44,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.Executor;
/**
* Class to handle interactions with {@link Slice}s.
@@ -64,6 +62,18 @@
"android.intent.action.REQUEST_SLICE_PERMISSION";
/**
+ * Category used to resolve intents that can be rendered as slices.
+ * <p>
+ * This category should be included on intent filters on providers that extend
+ * {@link SliceProvider}.
+ * @see SliceProvider
+ * @see SliceProvider#onMapIntentToUri(Intent)
+ * @see #mapIntentToUri(Intent)
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_SLICE = "android.app.slice.category.SLICE";
+
+ /**
* The meta-data key that allows an activity to easily be linked directly to a slice.
* <p>
* An activity can be statically linked to a slice uri by including a meta-data item
@@ -74,8 +84,6 @@
private final ISliceManager mService;
private final Context mContext;
- private final ArrayMap<Pair<Uri, SliceCallback>, ISliceListener> mListenerLookup =
- new ArrayMap<>();
private final IBinder mToken = new Binder();
/**
@@ -104,71 +112,6 @@
}
/**
- * @deprecated TO BE REMOVED.
- */
- @Deprecated
- public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback,
- @NonNull List<SliceSpec> specs) {
- }
-
- /**
- * @deprecated TO BE REMOVED.
- */
- @Deprecated
- public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback,
- @NonNull List<SliceSpec> specs, Executor executor) {
- }
-
- /**
- * Adds a callback to a specific slice uri.
- * <p>
- * This is a convenience that performs a few slice actions at once. It will put
- * the slice in a pinned state since there is a callback attached. It will also
- * listen for content changes, when a content change observes, the android system
- * will bind the new slice and provide it to all registered {@link SliceCallback}s.
- *
- * @param uri The uri of the slice being listened to.
- * @param callback The listener that should receive the callbacks.
- * @param specs The list of supported {@link SliceSpec}s of the callback.
- * @see SliceProvider#onSlicePinned(Uri)
- */
- public void registerSliceCallback(@NonNull Uri uri, @NonNull List<SliceSpec> specs,
- @NonNull SliceCallback callback) {
- }
-
- /**
- * Adds a callback to a specific slice uri.
- * <p>
- * This is a convenience that performs a few slice actions at once. It will put
- * the slice in a pinned state since there is a callback attached. It will also
- * listen for content changes, when a content change observes, the android system
- * will bind the new slice and provide it to all registered {@link SliceCallback}s.
- *
- * @param uri The uri of the slice being listened to.
- * @param callback The listener that should receive the callbacks.
- * @param specs The list of supported {@link SliceSpec}s of the callback.
- * @see SliceProvider#onSlicePinned(Uri)
- */
- public void registerSliceCallback(@NonNull Uri uri, @NonNull List<SliceSpec> specs,
- @NonNull @CallbackExecutor Executor executor, @NonNull SliceCallback callback) {
-
- }
-
- /**
- * Removes a callback for a specific slice uri.
- * <p>
- * Removes the app from the pinned state (if there are no other apps/callbacks pinning it)
- * in addition to removing the callback.
- *
- * @param uri The uri of the slice being listened to
- * @param callback The listener that should no longer receive callbacks.
- * @see #registerSliceCallback
- */
- public void unregisterSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback) {
-
- }
-
- /**
* Ensures that a slice is in a pinned state.
* <p>
* Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
@@ -297,6 +240,18 @@
/**
* Turns a slice intent into a slice uri. Expects an explicit intent.
+ * <p>
+ * This goes through a several stage resolution process to determine if any slice
+ * can represent this intent.
+ * - If the intent contains data that {@link ContentResolver#getType} is
+ * {@link SliceProvider#SLICE_TYPE} then the data will be returned.
+ * - If the intent with {@link #CATEGORY_SLICE} added resolves to a provider, then
+ * the provider will be asked to {@link SliceProvider#onMapIntentToUri} and that result
+ * will be returned.
+ * - Lastly, if the intent explicitly points at an activity, and that activity has
+ * meta-data for key {@link #SLICE_METADATA_KEY}, then the Uri specified there will be
+ * returned.
+ * - If no slice is found, then {@code null} is returned.
*
* @param intent The intent associated with a slice.
* @return The Slice Uri provided by the app or null if none exists.
@@ -316,8 +271,12 @@
return intentData;
}
// Otherwise ask the app
+ Intent queryIntent = new Intent(intent);
+ if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
+ queryIntent.addCategory(CATEGORY_SLICE);
+ }
List<ResolveInfo> providers =
- mContext.getPackageManager().queryIntentContentProviders(intent, 0);
+ mContext.getPackageManager().queryIntentContentProviders(queryIntent, 0);
if (providers == null || providers.isEmpty()) {
// There are no providers, see if this activity has a direct link.
ResolveInfo resolve = mContext.getPackageManager().resolveActivity(intent,
@@ -451,18 +410,4 @@
throw e.rethrowFromSystemServer();
}
}
-
- /**
- * Class that listens to changes in {@link Slice}s.
- */
- public interface SliceCallback {
-
- /**
- * Called when slice is updated.
- *
- * @param s The updated slice.
- * @see #registerSliceCallback
- */
- void onSliceUpdated(Slice s);
- }
}
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index af43032..df32fb9 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -65,8 +65,8 @@
* <pre class="prettyprint">
* {@literal
* <provider
- * android:name="com.android.mypkg.MySliceProvider"
- * android:authorities="com.android.mypkg" />}
+ * android:name="com.example.mypkg.MySliceProvider"
+ * android:authorities="com.example.mypkg" />}
* </pre>
* <p>
* Slices can be identified by a Uri or by an Intent. To link an Intent with a slice, the provider
@@ -77,10 +77,11 @@
* <pre class="prettyprint">
* {@literal
* <provider
- * android:name="com.android.mypkg.MySliceProvider"
- * android:authorities="com.android.mypkg">
+ * android:name="com.example.mypkg.MySliceProvider"
+ * android:authorities="com.example.mypkg">
* <intent-filter>
- * <action android:name="android.intent.action.MY_SLICE_INTENT" />
+ * <action android:name="com.example.mypkg.intent.action.MY_SLICE_INTENT" />
+ * <category android:name="android.app.slice.category.SLICE" />
* </intent-filter>
* </provider>}
* </pre>
@@ -253,8 +254,13 @@
* In that case, this method can be called and is expected to return a non-null Uri representing
* a slice. Otherwise this will throw {@link UnsupportedOperationException}.
*
+ * Any intent filter added to a slice provider should also contain
+ * {@link SliceManager#CATEGORY_SLICE}, because otherwise it will not be detected by
+ * {@link SliceManager#mapIntentToUri(Intent)}.
+ *
* @return Uri representing the slice associated with the provided intent.
- * @see {@link Slice}
+ * @see Slice
+ * @see SliceManager#mapIntentToUri(Intent)
*/
public @NonNull Uri onMapIntentToUri(Intent intent) {
throw new UnsupportedOperationException(
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e7aead1..ce32278 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2448,6 +2448,23 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
+
+
+ /**
+ * Broadcast Action: Sent when the current battery level changes.
+ *
+ * It has {@link android.os.BatteryManager#EXTRA_EVENTS} that carries a list of {@link Bundle}
+ * instances representing individual battery level changes with associated
+ * extras from {@link #ACTION_BATTERY_CHANGED}.
+ *
+ * <p class="note">
+ * This broadcast requires {@link android.Manifest.permission#BATTERY_STATS} permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_BATTERY_LEVEL_CHANGED =
+ "android.intent.action.BATTERY_LEVEL_CHANGED";
/**
* Broadcast Action: Indicates low battery condition on the device.
* This broadcast corresponds to the "Low battery warning" system dialog.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 4a8f61c..efa90d3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -763,15 +763,13 @@
public String[] resourceDirs;
/**
- * String retrieved from the seinfo tag found in selinux policy. This value
- * can be overridden with a value set through the mac_permissions.xml policy
- * construct. This value is useful in setting an SELinux security context on
- * the process as well as its data directory. The String default is being used
- * here to represent a catchall label when no policy matches.
+ * String retrieved from the seinfo tag found in selinux policy. This value can be set through
+ * the mac_permissions.xml policy construct. This value is used for setting an SELinux security
+ * context on the process as well as its data directory.
*
* {@hide}
*/
- public String seInfo = "default";
+ public String seInfo;
/**
* The seinfo tag generated per-user. This value may change based upon the
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 7717b8d..2a791ec 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -292,8 +292,10 @@
final boolean walEnabled =
(mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
// Use compatibility WAL unless an app explicitly set journal/synchronous mode
+ // or DISABLE_COMPATIBILITY_WAL flag is set
final boolean useCompatibilityWal = mConfiguration.journalMode == null
- && mConfiguration.syncMode == null && mConfiguration.useCompatibilityWal;
+ && mConfiguration.syncMode == null
+ && (mConfiguration.openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
if (walEnabled || useCompatibilityWal) {
setJournalMode("WAL");
if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
@@ -423,8 +425,8 @@
boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
!= mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
- & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0
- || configuration.useCompatibilityWal != mConfiguration.useCompatibilityWal;
+ & (SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING
+ | SQLiteDatabase.DISABLE_COMPATIBILITY_WAL)) != 0;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
// Update configuration parameters.
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index dc60612..dadb95b 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -315,7 +315,12 @@
}
}
- if (mConfiguration.openFlags != configuration.openFlags) {
+ // We should do in-place switching when transitioning from compatibility WAL
+ // to rollback journal. Otherwise transient connection state will be lost
+ boolean onlyCompatWalChanged = (mConfiguration.openFlags ^ configuration.openFlags)
+ == SQLiteDatabase.DISABLE_COMPATIBILITY_WAL;
+
+ if (!onlyCompatWalChanged && mConfiguration.openFlags != configuration.openFlags) {
// If we are changing open flags and WAL mode at the same time, then
// we have no choice but to close the primary connection beforehand
// because there can only be one connection open when we change WAL mode.
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index ae1f57d..b463d8d 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -253,6 +253,13 @@
public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
/**
+ * Open flag: Flag for {@link #openDatabase} to disable Compatibility WAL when opening database.
+ *
+ * @hide
+ */
+ public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
+
+ /**
* Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
*
* Each prepared-statement is between 1K - 6K, depending on the complexity of the
@@ -288,10 +295,10 @@
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
mConfigurationLocked.journalMode = journalMode;
mConfigurationLocked.syncMode = syncMode;
- mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported();
- if (!mConfigurationLocked.isInMemoryDb() && SQLiteCompatibilityWalFlags.areFlagsSet()) {
- mConfigurationLocked.useCompatibilityWal = SQLiteCompatibilityWalFlags
- .isCompatibilityWalSupported();
+ if (!SQLiteGlobal.isCompatibilityWalSupported() || (
+ SQLiteCompatibilityWalFlags.areFlagsSet() && !SQLiteCompatibilityWalFlags
+ .isCompatibilityWalSupported())) {
+ mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
}
}
@@ -2082,21 +2089,21 @@
synchronized (mLock) {
throwIfNotOpenLocked();
- final boolean oldUseCompatibilityWal = mConfigurationLocked.useCompatibilityWal;
final int oldFlags = mConfigurationLocked.openFlags;
- if (!oldUseCompatibilityWal && (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
+ final boolean walDisabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0;
+ final boolean compatibilityWalDisabled = (oldFlags & DISABLE_COMPATIBILITY_WAL) != 0;
+ if (walDisabled && compatibilityWalDisabled) {
return;
}
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
- // If an app explicitly disables WAL, do not even use compatibility mode
- mConfigurationLocked.useCompatibilityWal = false;
+ // If an app explicitly disables WAL, compatibility mode should be disabled too
+ mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
try {
mConnectionPoolLocked.reconfigure(mConfigurationLocked);
} catch (RuntimeException ex) {
mConfigurationLocked.openFlags = oldFlags;
- mConfigurationLocked.useCompatibilityWal = oldUseCompatibilityWal;
throw ex;
}
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index a14df1e..275043f 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -111,15 +111,6 @@
public long idleConnectionTimeoutMs = Long.MAX_VALUE;
/**
- * Enables compatibility WAL mode. Applications cannot explicitly choose compatibility WAL mode,
- * therefore it is not exposed as a flag.
- *
- * <p>In this mode, only database journal mode will be changed, connection pool
- * size will still be limited to a single connection.
- */
- public boolean useCompatibilityWal;
-
- /**
* Journal mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set.
* <p>Default is returned by {@link SQLiteGlobal#getDefaultJournalMode()}
*/
@@ -191,7 +182,6 @@
lookasideSlotSize = other.lookasideSlotSize;
lookasideSlotCount = other.lookasideSlotCount;
idleConnectionTimeoutMs = other.idleConnectionTimeoutMs;
- useCompatibilityWal = other.useCompatibilityWal;
journalMode = other.journalMode;
syncMode = other.syncMode;
}
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 64e9e5d..7ff6635 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -197,6 +197,8 @@
}
mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);
}
+ // Compatibility WAL is disabled if an app disables or enables WAL
+ mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.DISABLE_COMPATIBILITY_WAL);
}
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 72db33f..f47d464 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -819,7 +819,8 @@
* @param config A session configuration (see {@link SessionConfiguration}).
*
* @throws IllegalArgumentException In case the session configuration is invalid; or the output
- * configurations are empty.
+ * configurations are empty; or the session configuration
+ * executor is invalid.
* @throws CameraAccessException In case the camera device is no longer connected or has
* encountered a fatal error.
* @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
diff --git a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java b/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
deleted file mode 100644
index 866f370..0000000
--- a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * A dispatcher that replaces one argument with another; replaces any argument at an index
- * with another argument.
- *
- * <p>For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always
- * equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to
- * be something
- * that's not an {@code int}.</p>
- *
- * @param <T>
- * source dispatch type, whose methods with {@link #dispatch} will be called
- * @param <TArg>
- * argument replacement type, args in {@link #dispatch} matching {@code argumentIndex}
- * will be overriden to objects of this type
- */
-public class ArgumentReplacingDispatcher<T, TArg> implements Dispatchable<T> {
-
- private final Dispatchable<T> mTarget;
- private final int mArgumentIndex;
- private final TArg mReplaceWith;
-
- /**
- * Create a new argument replacing dispatcher; dispatches are forwarded to {@code target}
- * after the argument is replaced.
- *
- * <p>For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted
- * to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set
- * {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.</p>
- *
- * <p>If a method dispatched has less arguments than {@code argumentIndex}, it is
- * passed through with the arguments unchanged.</p>
- *
- * @param target destination dispatch type, methods will be redirected to this dispatcher
- * @param argumentIndex the numeric index of the argument {@code >= 0}
- * @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object
- */
- public ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex,
- TArg replaceWith) {
- mTarget = checkNotNull(target, "target must not be null");
- mArgumentIndex = checkArgumentNonnegative(argumentIndex,
- "argumentIndex must not be negative");
- mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null");
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) throws Throwable {
-
- if (args.length > mArgumentIndex) {
- args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches
- args[mArgumentIndex] = mReplaceWith;
- }
-
- return mTarget.dispatch(method, args);
- }
-
- private static Object[] arrayCopy(Object[] array) {
- int length = array.length;
- Object[] newArray = new Object[length];
- for (int i = 0; i < length; ++i) {
- newArray[i] = array[i];
- }
- return newArray;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java b/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
deleted file mode 100644
index fe575b2..0000000
--- a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Broadcast a single dispatch into multiple other dispatchables.
- *
- * <p>Every time {@link #dispatch} is invoked, all the broadcast targets will
- * see the same dispatch as well. The first target's return value is returned.</p>
- *
- * <p>This enables a single listener to be converted into a multi-listener.</p>
- */
-public class BroadcastDispatcher<T> implements Dispatchable<T> {
-
- private final List<Dispatchable<T>> mDispatchTargets;
-
- /**
- * Create a broadcast dispatcher from the supplied dispatch targets.
- *
- * @param dispatchTargets one or more targets to dispatch to
- */
- @SafeVarargs
- public BroadcastDispatcher(Dispatchable<T>... dispatchTargets) {
- mDispatchTargets = Arrays.asList(
- checkNotNull(dispatchTargets, "dispatchTargets must not be null"));
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) throws Throwable {
- Object result = null;
- boolean gotResult = false;
-
- for (Dispatchable<T> dispatchTarget : mDispatchTargets) {
- Object localResult = dispatchTarget.dispatch(method, args);
-
- if (!gotResult) {
- gotResult = true;
- result = localResult;
- }
- }
-
- return result;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/Dispatchable.java b/core/java/android/hardware/camera2/dispatch/Dispatchable.java
deleted file mode 100644
index 753103f..0000000
--- a/core/java/android/hardware/camera2/dispatch/Dispatchable.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-import java.lang.reflect.Method;
-
-/**
- * Dynamically dispatch a method and its argument to some object.
- *
- * <p>This can be used to intercept method calls and do work around them, redirect work,
- * or block calls entirely.</p>
- */
-public interface Dispatchable<T> {
- /**
- * Dispatch the method and arguments to this object.
- * @param method a method defined in class {@code T}
- * @param args arguments corresponding to said {@code method}
- * @return the object returned when invoking {@code method}
- * @throws Throwable any exception that might have been raised while invoking the method
- */
- public Object dispatch(Method method, Object[] args) throws Throwable;
-}
diff --git a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java b/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
deleted file mode 100644
index 75f97e4..0000000
--- a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Duck typing dispatcher; converts dispatch methods calls from one class to another by
- * looking up equivalently methods at runtime by name.
- *
- * <p>For example, if two types have identical method names and arguments, but
- * are not subclasses/subinterfaces of each other, this dispatcher will allow calls to be
- * made from one type to the other.</p>
- *
- * @param <TFrom> source dispatch type, whose methods with {@link #dispatch} will be called
- * @param <T> destination dispatch type, methods will be converted to the class of {@code T}
- */
-public class DuckTypingDispatcher<TFrom, T> implements Dispatchable<TFrom> {
-
- private final MethodNameInvoker<T> mDuck;
-
- /**
- * Create a new duck typing dispatcher.
- *
- * @param target destination dispatch type, methods will be redirected to this dispatcher
- * @param targetClass destination dispatch class, methods will be converted to this class's
- */
- public DuckTypingDispatcher(Dispatchable<T> target, Class<T> targetClass) {
- checkNotNull(targetClass, "targetClass must not be null");
- checkNotNull(target, "target must not be null");
-
- mDuck = new MethodNameInvoker<T>(target, targetClass);
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) {
- return mDuck.invoke(method.getName(), args);
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java b/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
deleted file mode 100644
index f8e9d49..0000000
--- a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.os.Handler;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Forward all interface calls into a handler by posting it as a {@code Runnable}.
- *
- * <p>All calls will return immediately; functions with return values will return a default
- * value of {@code null}, {@code 0}, or {@code false} where that value is legal.</p>
- *
- * <p>Any exceptions thrown on the handler while trying to invoke a method
- * will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any
- * checked exceptions to be thrown will result in "undefined" behavior
- * (although in practice it is usually thrown as normal).</p>
- */
-public class HandlerDispatcher<T> implements Dispatchable<T> {
-
- private static final String TAG = "HandlerDispatcher";
-
- private final Dispatchable<T> mDispatchTarget;
- private final Handler mHandler;
-
- /**
- * Create a dispatcher that forwards it's dispatch calls by posting
- * them onto the {@code handler} as a {@code Runnable}.
- *
- * @param dispatchTarget the destination whose method calls will be redirected into the handler
- * @param handler all calls into {@code dispatchTarget} will be posted onto this handler
- * @param <T> the type of the element you want to wrap.
- * @return a dispatcher that will forward it's dispatch calls to a handler
- */
- public HandlerDispatcher(Dispatchable<T> dispatchTarget, Handler handler) {
- mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mHandler = checkNotNull(handler, "handler must not be null");
- }
-
- @Override
- public Object dispatch(final Method method, final Object[] args) throws Throwable {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- mDispatchTarget.dispatch(method, args);
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- // Potential UB. Hopefully 't' is a runtime exception.
- UncheckedThrow.throwAnyException(t);
- } catch (IllegalAccessException e) {
- // Impossible
- Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
- } catch (IllegalArgumentException e) {
- // Impossible
- Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
- } catch (Throwable e) {
- UncheckedThrow.throwAnyException(e);
- }
- }
- });
-
- // TODO handle primitive return values that would avoid NPE if unboxed
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java b/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
deleted file mode 100644
index ac5f526..0000000
--- a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-
-public class InvokeDispatcher<T> implements Dispatchable<T> {
-
- private static final String TAG = "InvocationSink";
- private final T mTarget;
-
- public InvokeDispatcher(T target) {
- mTarget = checkNotNull(target, "target must not be null");
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) {
- try {
- return method.invoke(mTarget, args);
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- // Potential UB. Hopefully 't' is a runtime exception.
- UncheckedThrow.throwAnyException(t);
- } catch (IllegalAccessException e) {
- // Impossible
- Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
- } catch (IllegalArgumentException e) {
- // Impossible
- Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
- }
-
- // unreachable
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
deleted file mode 100644
index 8296b7a..0000000
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
- *
- * @param <T> destination dispatch type, methods will be looked up in the class of {@code T}
- */
-public class MethodNameInvoker<T> {
-
- private final Dispatchable<T> mTarget;
- private final Class<T> mTargetClass;
- private final Method[] mTargetClassMethods;
- private final ConcurrentHashMap<String, Method> mMethods =
- new ConcurrentHashMap<>();
-
- /**
- * Create a new method name invoker.
- *
- * @param target destination dispatch type, invokes will be redirected to this dispatcher
- * @param targetClass destination dispatch class, the invoked methods will be from this class
- */
- public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) {
- mTargetClass = targetClass;
- mTargetClassMethods = targetClass.getMethods();
- mTarget = target;
- }
-
- /**
- * Invoke a method by its name.
- *
- * <p>If more than one method exists in {@code targetClass}, the first method with the right
- * number of arguments will be used, and later calls will all use that method.</p>
- *
- * @param methodName
- * The name of the method, which will be matched 1:1 to the destination method
- * @param params
- * Variadic parameter list.
- * @return
- * The same kind of value that would normally be returned by calling {@code methodName}
- * statically.
- *
- * @throws IllegalArgumentException if {@code methodName} does not exist on the target class
- * @throws Throwable will rethrow anything that the target method would normally throw
- */
- @SuppressWarnings("unchecked")
- public <K> K invoke(String methodName, Object... params) {
- checkNotNull(methodName, "methodName must not be null");
-
- Method targetMethod = mMethods.get(methodName);
- if (targetMethod == null) {
- for (Method method : mTargetClassMethods) {
- // TODO future: match types of params if possible
- if (method.getName().equals(methodName) &&
- (params.length == method.getParameterTypes().length) ) {
- targetMethod = method;
- mMethods.put(methodName, targetMethod);
- break;
- }
- }
-
- if (targetMethod == null) {
- throw new IllegalArgumentException(
- "Method " + methodName + " does not exist on class " + mTargetClass);
- }
- }
-
- try {
- return (K) mTarget.dispatch(targetMethod, params);
- } catch (Throwable e) {
- UncheckedThrow.throwAnyException(e);
- // unreachable
- return null;
- }
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java b/core/java/android/hardware/camera2/dispatch/NullDispatcher.java
deleted file mode 100644
index fada075..0000000
--- a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-
-/**
- * Do nothing when dispatching; follows the null object pattern.
- */
-public class NullDispatcher<T> implements Dispatchable<T> {
- /**
- * Create a dispatcher that does nothing when dispatched to.
- */
- public NullDispatcher() {
- }
-
- /**
- * Do nothing; all parameters are ignored.
- */
- @Override
- public Object dispatch(Method method, Object[] args) {
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/package.html b/core/java/android/hardware/camera2/dispatch/package.html
deleted file mode 100644
index 783d0a1..0000000
--- a/core/java/android/hardware/camera2/dispatch/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body>
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index c9eecf1..9e4cb80 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -15,16 +15,17 @@
*/
package android.hardware.camera2.impl;
+import android.os.Binder;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
-import android.hardware.camera2.dispatch.Dispatchable;
-import android.hardware.camera2.dispatch.MethodNameInvoker;
import android.view.Surface;
+import java.util.concurrent.Executor;
+
import static com.android.internal.util.Preconditions.*;
/**
@@ -34,164 +35,86 @@
* to use our own proxy mechanism.</p>
*/
public class CallbackProxies {
-
- // TODO: replace with codegen
-
- public static class DeviceStateCallbackProxy extends CameraDeviceImpl.StateCallbackKK {
- private final MethodNameInvoker<CameraDeviceImpl.StateCallbackKK> mProxy;
-
- public DeviceStateCallbackProxy(
- Dispatchable<CameraDeviceImpl.StateCallbackKK> dispatchTarget) {
- dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateCallbackKK.class);
- }
-
- @Override
- public void onOpened(CameraDevice camera) {
- mProxy.invoke("onOpened", camera);
- }
-
- @Override
- public void onDisconnected(CameraDevice camera) {
- mProxy.invoke("onDisconnected", camera);
- }
-
- @Override
- public void onError(CameraDevice camera, int error) {
- mProxy.invoke("onError", camera, error);
- }
-
- @Override
- public void onUnconfigured(CameraDevice camera) {
- mProxy.invoke("onUnconfigured", camera);
- }
-
- @Override
- public void onActive(CameraDevice camera) {
- mProxy.invoke("onActive", camera);
- }
-
- @Override
- public void onBusy(CameraDevice camera) {
- mProxy.invoke("onBusy", camera);
- }
-
- @Override
- public void onClosed(CameraDevice camera) {
- mProxy.invoke("onClosed", camera);
- }
-
- @Override
- public void onIdle(CameraDevice camera) {
- mProxy.invoke("onIdle", camera);
- }
- }
-
- @SuppressWarnings("deprecation")
- public static class DeviceCaptureCallbackProxy implements CameraDeviceImpl.CaptureCallback {
- private final MethodNameInvoker<CameraDeviceImpl.CaptureCallback> mProxy;
-
- public DeviceCaptureCallbackProxy(
- Dispatchable<CameraDeviceImpl.CaptureCallback> dispatchTarget) {
- dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureCallback.class);
- }
-
- @Override
- public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp, long frameNumber) {
- mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber);
- }
-
- @Override
- public void onCapturePartial(CameraDevice camera,
- CaptureRequest request, CaptureResult result) {
- mProxy.invoke("onCapturePartial", camera, request, result);
- }
-
- @Override
- public void onCaptureProgressed(CameraDevice camera,
- CaptureRequest request, CaptureResult partialResult) {
- mProxy.invoke("onCaptureProgressed", camera, request, partialResult);
- }
-
- @Override
- public void onCaptureCompleted(CameraDevice camera,
- CaptureRequest request, TotalCaptureResult result) {
- mProxy.invoke("onCaptureCompleted", camera, request, result);
- }
-
- @Override
- public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request, CaptureFailure failure) {
- mProxy.invoke("onCaptureFailed", camera, request, failure);
- }
-
- @Override
- public void onCaptureSequenceCompleted(CameraDevice camera,
- int sequenceId, long frameNumber) {
- mProxy.invoke("onCaptureSequenceCompleted", camera, sequenceId, frameNumber);
- }
-
- @Override
- public void onCaptureSequenceAborted(CameraDevice camera,
- int sequenceId) {
- mProxy.invoke("onCaptureSequenceAborted", camera, sequenceId);
- }
-
- @Override
- public void onCaptureBufferLost(CameraDevice camera,
- CaptureRequest request, Surface target, long frameNumber) {
- mProxy.invoke("onCaptureBufferLost", camera, request, target, frameNumber);
- }
-
- }
-
public static class SessionStateCallbackProxy
extends CameraCaptureSession.StateCallback {
- private final MethodNameInvoker<CameraCaptureSession.StateCallback> mProxy;
+ private final Executor mExecutor;
+ private final CameraCaptureSession.StateCallback mCallback;
- public SessionStateCallbackProxy(
- Dispatchable<CameraCaptureSession.StateCallback> dispatchTarget) {
- dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget,
- CameraCaptureSession.StateCallback.class);
+ public SessionStateCallbackProxy(Executor executor,
+ CameraCaptureSession.StateCallback callback) {
+ mExecutor = checkNotNull(executor, "executor must not be null");
+ mCallback = checkNotNull(callback, "callback must not be null");
}
@Override
public void onConfigured(CameraCaptureSession session) {
- mProxy.invoke("onConfigured", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onConfigured(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
- mProxy.invoke("onConfigureFailed", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onConfigureFailed(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onReady(CameraCaptureSession session) {
- mProxy.invoke("onReady", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onReady(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onActive(CameraCaptureSession session) {
- mProxy.invoke("onActive", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onActive(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onCaptureQueueEmpty(CameraCaptureSession session) {
- mProxy.invoke("onCaptureQueueEmpty", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onCaptureQueueEmpty(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onClosed(CameraCaptureSession session) {
- mProxy.invoke("onClosed", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onClosed(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
- mProxy.invoke("onSurfacePrepared", session, surface);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onSurfacePrepared(session, surface));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 8b8bbc3..f3f6c84 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -20,20 +20,18 @@
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.dispatch.ArgumentReplacingDispatcher;
-import android.hardware.camera2.dispatch.BroadcastDispatcher;
-import android.hardware.camera2.dispatch.DuckTypingDispatcher;
-import android.hardware.camera2.dispatch.HandlerDispatcher;
-import android.hardware.camera2.dispatch.InvokeDispatcher;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.TaskDrainer;
import android.hardware.camera2.utils.TaskSingleDrainer;
+import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.util.Log;
import android.view.Surface;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler;
import static com.android.internal.util.Preconditions.*;
@@ -51,11 +49,11 @@
private final Surface mInput;
/**
* User-specified state callback, used for outgoing events; calls to this object will be
- * automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}.
+ * automatically invoked via {@code mStateExecutor}.
*/
private final CameraCaptureSession.StateCallback mStateCallback;
- /** User-specified state handler used for outgoing state callback events */
- private final Handler mStateHandler;
+ /** User-specified state executor used for outgoing state callback events */
+ private final Executor mStateExecutor;
/** Internal camera device; used to translate calls into existing deprecated API */
private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl;
@@ -87,7 +85,7 @@
* (e.g. no pending captures, no repeating requests, no flush).</p>
*/
CameraCaptureSessionImpl(int id, Surface input,
- CameraCaptureSession.StateCallback callback, Handler stateHandler,
+ CameraCaptureSession.StateCallback callback, Executor stateExecutor,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
Handler deviceStateHandler, boolean configureSuccess) {
if (callback == null) {
@@ -98,8 +96,8 @@
mIdString = String.format("Session %d: ", mId);
mInput = input;
- mStateHandler = checkHandler(stateHandler);
- mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
+ mStateExecutor = checkNotNull(stateExecutor, "stateExecutor must not be null");
+ mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback);
mDeviceHandler = checkNotNull(deviceStateHandler, "deviceStateHandler must not be null");
mDeviceImpl = checkNotNull(deviceImpl, "deviceImpl must not be null");
@@ -110,12 +108,12 @@
* This ensures total ordering between CameraDevice.StateCallback and
* CameraDeviceImpl.CaptureCallback events.
*/
- mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
- /*name*/"seq");
- mIdleDrainer = new TaskSingleDrainer(mDeviceHandler, new IdleDrainListener(),
- /*name*/"idle");
- mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
- /*name*/"abort");
+ mSequenceDrainer = new TaskDrainer<>(new HandlerExecutor(mDeviceHandler),
+ new SequenceDrainListener(), /*name*/"seq");
+ mIdleDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
+ new IdleDrainListener(), /*name*/"idle");
+ mAbortDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
+ new AbortDrainListener(), /*name*/"abort");
// CameraDevice should call configureOutputs and have it finish before constructing us
@@ -446,114 +444,140 @@
}
/**
- * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code handler}.
+ * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code executor}.
*/
- private StateCallback createUserStateCallbackProxy(Handler handler, StateCallback callback) {
- InvokeDispatcher<StateCallback> userCallbackSink = new InvokeDispatcher<>(callback);
- HandlerDispatcher<StateCallback> handlerPassthrough =
- new HandlerDispatcher<>(userCallbackSink, handler);
-
- return new CallbackProxies.SessionStateCallbackProxy(handlerPassthrough);
+ private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) {
+ return new CallbackProxies.SessionStateCallbackProxy(executor, callback);
}
/**
* Forward callbacks from
* CameraDeviceImpl.CaptureCallback to the CameraCaptureSession.CaptureCallback.
*
- * <p>In particular, all calls are automatically split to go both to our own
- * internal callback, and to the user-specified callback (by transparently posting
- * to the user-specified handler).</p>
- *
* <p>When a capture sequence finishes, update the pending checked sequences set.</p>
*/
@SuppressWarnings("deprecation")
private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy(
Handler handler, CaptureCallback callback) {
- CameraDeviceImpl.CaptureCallback localCallback = new CameraDeviceImpl.CaptureCallback() {
+ final Executor executor = (callback != null) ? CameraDeviceImpl.checkAndWrapHandler(
+ handler) : null;
+ return new CameraDeviceImpl.CaptureCallback() {
@Override
public void onCaptureStarted(CameraDevice camera,
CaptureRequest request, long timestamp, long frameNumber) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureStarted(
+ CameraCaptureSessionImpl.this, request, timestamp,
+ frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCapturePartial(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureResult result) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCapturePartial(
+ CameraCaptureSessionImpl.this, request, result));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureProgressed(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureProgressed(
+ CameraCaptureSessionImpl.this, request, partialResult));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureCompleted(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureCompleted(
+ CameraCaptureSessionImpl.this, request, result));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureFailed(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureFailure failure) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureFailed(
+ CameraCaptureSessionImpl.this, request, failure));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureSequenceCompleted(CameraDevice camera,
int sequenceId, long frameNumber) {
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureSequenceCompleted(
+ CameraCaptureSessionImpl.this, sequenceId, frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
finishPendingSequence(sequenceId);
}
@Override
public void onCaptureSequenceAborted(CameraDevice camera,
int sequenceId) {
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureSequenceAborted(
+ CameraCaptureSessionImpl.this, sequenceId));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
finishPendingSequence(sequenceId);
}
@Override
public void onCaptureBufferLost(CameraDevice camera,
CaptureRequest request, Surface target, long frameNumber) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureBufferLost(
+ CameraCaptureSessionImpl.this, request, target, frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
-
};
-
- /*
- * Split the calls from the device callback into local callback and the following chain:
- * - replace the first CameraDevice arg with a CameraCaptureSession
- * - duck type from device callback to session callback
- * - then forward the call to a handler
- * - then finally invoke the destination method on the session callback object
- */
- if (callback == null) {
- // OK: API allows the user to not specify a callback, and the handler may
- // also be null in that case. Collapse whole dispatch chain to only call the local
- // callback
- return localCallback;
- }
-
- InvokeDispatcher<CameraDeviceImpl.CaptureCallback> localSink =
- new InvokeDispatcher<>(localCallback);
-
- InvokeDispatcher<CaptureCallback> userCallbackSink =
- new InvokeDispatcher<>(callback);
- HandlerDispatcher<CaptureCallback> handlerPassthrough =
- new HandlerDispatcher<>(userCallbackSink, handler);
- DuckTypingDispatcher<CameraDeviceImpl.CaptureCallback, CaptureCallback> duckToSession
- = new DuckTypingDispatcher<>(handlerPassthrough, CaptureCallback.class);
- ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureCallback, CameraCaptureSessionImpl>
- replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
- /*argumentIndex*/0, this);
-
- BroadcastDispatcher<CameraDeviceImpl.CaptureCallback> broadcaster =
- new BroadcastDispatcher<CameraDeviceImpl.CaptureCallback>(
- replaceDeviceWithSession,
- localSink);
-
- return new CallbackProxies.DeviceCaptureCallbackProxy(broadcaster);
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 06c2c25..4ee08ba 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -33,6 +33,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.Executor;
import static com.android.internal.util.Preconditions.*;
@@ -59,14 +60,14 @@
* (e.g. no pending captures, no repeating requests, no flush).</p>
*/
CameraConstrainedHighSpeedCaptureSessionImpl(int id,
- CameraCaptureSession.StateCallback callback, Handler stateHandler,
+ CameraCaptureSession.StateCallback callback, Executor stateExecutor,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
Handler deviceStateHandler, boolean configureSuccess,
CameraCharacteristics characteristics) {
mCharacteristics = characteristics;
CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
- stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
+ stateExecutor, deviceImpl, deviceStateHandler, configureSuccess);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 511fa43..b328bb1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -35,8 +35,10 @@
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SurfaceUtils;
+import android.os.Binder;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -58,6 +60,7 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Executor;
/**
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -501,8 +504,9 @@
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(null, outConfigurations, callback, handler,
- /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
+ createCaptureSessionInternal(null, outConfigurations, callback,
+ checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
+ /*sessionParams*/ null);
}
@Override
@@ -517,7 +521,7 @@
// OutputConfiguration objects are immutable, but need to have our own array
List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations);
- createCaptureSessionInternal(null, currentOutputs, callback, handler,
+ createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler),
/*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null);
}
@@ -537,8 +541,9 @@
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler,
- /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
+ createCaptureSessionInternal(inputConfig, outConfigurations, callback,
+ checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
+ /*sessionParams*/ null);
}
@Override
@@ -566,8 +571,8 @@
currentOutputs.add(new OutputConfiguration(output));
}
createCaptureSessionInternal(inputConfig, currentOutputs,
- callback, handler, /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
- /*sessionParams*/ null);
+ callback, checkAndWrapHandler(handler),
+ /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
}
@Override
@@ -582,7 +587,8 @@
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(null, outConfigurations, callback, handler,
+ createCaptureSessionInternal(null, outConfigurations, callback,
+ checkAndWrapHandler(handler),
/*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
/*sessionParams*/ null);
}
@@ -597,8 +603,8 @@
for (OutputConfiguration output : outputs) {
currentOutputs.add(new OutputConfiguration(output));
}
- createCaptureSessionInternal(inputConfig, currentOutputs, callback, handler, operatingMode,
- /*sessionParams*/ null);
+ createCaptureSessionInternal(inputConfig, currentOutputs, callback,
+ checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
}
@Override
@@ -612,14 +618,17 @@
if (outputConfigs == null) {
throw new IllegalArgumentException("Invalid output configurations");
}
+ if (config.getExecutor() == null) {
+ throw new IllegalArgumentException("Invalid executor");
+ }
createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
- config.getStateCallback(), config.getHandler(), config.getSessionType(),
+ config.getStateCallback(), config.getExecutor(), config.getSessionType(),
config.getSessionParameters());
}
private void createCaptureSessionInternal(InputConfiguration inputConfig,
List<OutputConfiguration> outputConfigurations,
- CameraCaptureSession.StateCallback callback, Handler handler,
+ CameraCaptureSession.StateCallback callback, Executor executor,
int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
synchronized(mInterfaceLock) {
if (DEBUG) {
@@ -673,12 +682,11 @@
SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
- callback, handler, this, mDeviceHandler, configureSuccess,
+ callback, executor, this, mDeviceHandler, configureSuccess,
mCharacteristics);
} else {
newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
- callback, handler, this, mDeviceHandler,
- configureSuccess);
+ callback, executor, this, mDeviceHandler, configureSuccess);
}
// TODO: wait until current session closes, then create the new session
@@ -963,7 +971,12 @@
}
}
};
- holder.getHandler().post(resultDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(resultDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
} else {
Log.w(TAG, String.format(
"did not register callback to request %d",
@@ -984,9 +997,9 @@
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Handler handler, boolean repeating) throws CameraAccessException {
- // Need a valid handler, or current thread needs to have a looper, if
+ // Need a valid executor, or current thread needs to have a looper, if
// callback is valid
- handler = checkHandler(handler, callback);
+ Executor executor = getExecutor(handler, callback);
// Make sure that there all requests have at least 1 surface; all surfaces are non-null;
// the surface isn't a physical stream surface for reprocessing request
@@ -1040,7 +1053,7 @@
if (callback != null) {
mCaptureCallbackMap.put(requestInfo.getRequestId(),
new CaptureCallbackHolder(
- callback, requestList, handler, repeating, mNextSessionId - 1));
+ callback, requestList, executor, repeating, mNextSessionId - 1));
} else {
if (DEBUG) {
Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
@@ -1354,7 +1367,7 @@
private final boolean mRepeating;
private final CaptureCallback mCallback;
private final List<CaptureRequest> mRequestList;
- private final Handler mHandler;
+ private final Executor mExecutor;
private final int mSessionId;
/**
* <p>Determine if the callback holder is for a constrained high speed request list that
@@ -1366,13 +1379,13 @@
private final boolean mHasBatchedOutputs;
CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
- Handler handler, boolean repeating, int sessionId) {
- if (callback == null || handler == null) {
+ Executor executor, boolean repeating, int sessionId) {
+ if (callback == null || executor == null) {
throw new UnsupportedOperationException(
"Must have a valid handler and a valid callback");
}
mRepeating = repeating;
- mHandler = handler;
+ mExecutor = executor;
mRequestList = new ArrayList<CaptureRequest>(requestList);
mCallback = callback;
mSessionId = sessionId;
@@ -1425,8 +1438,8 @@
return getRequest(0);
}
- public Handler getHandler() {
- return mHandler;
+ public Executor getExecutor() {
+ return mExecutor;
}
public int getSessionId() {
@@ -1810,7 +1823,12 @@
}
}
};
- holder.getHandler().post(resultDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(resultDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
}
@@ -1861,7 +1879,7 @@
private void scheduleNotifyError(int code) {
mInError = true;
CameraDeviceImpl.this.mDeviceHandler.post(obtainRunnable(
- CameraDeviceCallbacks::notifyError, this, code));
+ CameraDeviceCallbacks::notifyError, this, code));
}
private void notifyError(int code) {
@@ -1929,36 +1947,41 @@
if (isClosed()) return;
// Dispatch capture start notice
- holder.getHandler().post(
- new Runnable() {
- @Override
- public void run() {
- if (!CameraDeviceImpl.this.isClosed()) {
- final int subsequenceId = resultExtras.getSubsequenceId();
- final CaptureRequest request = holder.getRequest(subsequenceId);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (!CameraDeviceImpl.this.isClosed()) {
+ final int subsequenceId = resultExtras.getSubsequenceId();
+ final CaptureRequest request = holder.getRequest(subsequenceId);
- if (holder.hasBatchedOutputs()) {
- // Send derived onCaptureStarted for requests within the batch
- final Range<Integer> fpsRange =
- request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
- for (int i = 0; i < holder.getRequestCount(); i++) {
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureStarted for requests within the
+ // batch
+ final Range<Integer> fpsRange =
+ request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ holder.getCallback().onCaptureStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ timestamp - (subsequenceId - i) *
+ NANO_PER_SECOND/fpsRange.getUpper(),
+ frameNumber - (subsequenceId - i));
+ }
+ } else {
holder.getCallback().onCaptureStarted(
CameraDeviceImpl.this,
- holder.getRequest(i),
- timestamp - (subsequenceId - i) *
- NANO_PER_SECOND/fpsRange.getUpper(),
- frameNumber - (subsequenceId - i));
+ holder.getRequest(resultExtras.getSubsequenceId()),
+ timestamp, frameNumber);
}
- } else {
- holder.getCallback().onCaptureStarted(
- CameraDeviceImpl.this,
- holder.getRequest(resultExtras.getSubsequenceId()),
- timestamp, frameNumber);
}
}
- }
- });
-
+ });
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -2111,7 +2134,12 @@
finalResult = resultAsCapture;
}
- holder.getHandler().post(resultDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(resultDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
// Collect the partials for a total result; or mark the frame as totally completed
mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
@@ -2207,7 +2235,12 @@
}
};
// Dispatch the failure callback
- holder.getHandler().post(failureDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(failureDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
} else {
boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
@@ -2247,7 +2280,12 @@
checkAndFireSequenceComplete();
// Dispatch the failure callback
- holder.getHandler().post(failureDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(failureDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -2255,6 +2293,37 @@
} // public class CameraDeviceCallbacks
/**
+ * Instantiate a new Executor.
+ *
+ * <p>If the callback isn't null, check the handler and instantiate a new executor,
+ * otherwise instantiate a new executor in case handler is valid.</p>
+ */
+ static <T> Executor getExecutor(Handler handler, T callback) {
+ if (callback != null) {
+ return checkAndWrapHandler(handler);
+ }
+
+ if (handler != null) {
+ return new HandlerExecutor(handler);
+ }
+
+ return null;
+ }
+
+ /**
+ * Wrap Handler in Executor.
+ *
+ * <p>
+ * If handler is null, get the current thread's
+ * Looper to create a Executor with. If no looper exists, throw
+ * {@code IllegalArgumentException}.
+ * </p>
+ */
+ static Executor checkAndWrapHandler(Handler handler) {
+ return new HandlerExecutor(checkHandler(handler));
+ }
+
+ /**
* Default handler management.
*
* <p>
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index a79a6c1..7bdb4a2 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -17,10 +17,10 @@
package android.hardware.camera2.params;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.IntDef;
-import android.os.Handler;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
@@ -31,6 +31,7 @@
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
+import java.util.concurrent.Executor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -78,7 +79,7 @@
private List<OutputConfiguration> mOutputConfigurations;
private CameraCaptureSession.StateCallback mStateCallback;
private int mSessionType;
- private Handler mHandler = null;
+ private Executor mExecutor = null;
private InputConfiguration mInputConfig = null;
private CaptureRequest mSessionParameters = null;
@@ -87,10 +88,9 @@
*
* @param sessionType The session type.
* @param outputs A list of output configurations for the capture session.
+ * @param executor The executor which should be used to invoke the callback. In general it is
+ * recommended that camera operations are not done on the main (UI) thread.
* @param cb A state callback interface implementation.
- * @param handler The handler on which the callback will be invoked. If it is
- * set to null, the callback will be invoked on the current thread's
- * {@link android.os.Looper looper}.
*
* @see #SESSION_REGULAR
* @see #SESSION_HIGH_SPEED
@@ -101,11 +101,12 @@
*/
public SessionConfiguration(@SessionMode int sessionType,
@NonNull List<OutputConfiguration> outputs,
- @NonNull CameraCaptureSession.StateCallback cb, @Nullable Handler handler) {
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CameraCaptureSession.StateCallback cb) {
mSessionType = sessionType;
mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
mStateCallback = cb;
- mHandler = handler;
+ mExecutor = executor;
}
/**
@@ -136,14 +137,12 @@
}
/**
- * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
+ * Retrieve the {@link java.util.concurrent.Executor} for the capture session.
*
- * @return The handler on which the callback will be invoked. If it is
- * set to null, the callback will be invoked on the current thread's
- * {@link android.os.Looper looper}.
+ * @return The Executor on which the callback will be invoked.
*/
- public Handler getHandler() {
- return mHandler;
+ public Executor getExecutor() {
+ return mExecutor;
}
/**
diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
index ed30ff3..e71f26a 100644
--- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
@@ -15,11 +15,11 @@
*/
package android.hardware.camera2.utils;
-import android.os.Handler;
import android.util.Log;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.Executor;
import static com.android.internal.util.Preconditions.*;
@@ -55,7 +55,7 @@
private static final String TAG = "TaskDrainer";
private final boolean DEBUG = false;
- private final Handler mHandler;
+ private final Executor mExecutor;
private final DrainListener mListener;
private final String mName;
@@ -73,28 +73,27 @@
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
*/
- public TaskDrainer(Handler handler, DrainListener listener) {
- mHandler = checkNotNull(handler, "handler must not be null");
+ public TaskDrainer(Executor executor, DrainListener listener) {
+ mExecutor = checkNotNull(executor, "executor must not be null");
mListener = checkNotNull(listener, "listener must not be null");
mName = null;
}
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
* @param name an optional name used for debug logging
*/
- public TaskDrainer(Handler handler, DrainListener listener, String name) {
- // XX: Probably don't need a handler at all here
- mHandler = checkNotNull(handler, "handler must not be null");
+ public TaskDrainer(Executor executor, DrainListener listener, String name) {
+ mExecutor = checkNotNull(executor, "executor must not be null");
mListener = checkNotNull(listener, "listener must not be null");
mName = name;
}
@@ -200,15 +199,12 @@
}
private void postDrained() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
+ mExecutor.execute(() -> {
if (DEBUG) {
Log.v(TAG + "[" + mName + "]", "onDrained");
}
mListener.onDrained();
- }
});
}
}
diff --git a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
index f6272c9..9615450 100644
--- a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
@@ -16,7 +16,8 @@
package android.hardware.camera2.utils;
import android.hardware.camera2.utils.TaskDrainer.DrainListener;
-import android.os.Handler;
+
+import java.util.concurrent.Executor;
/**
* Keep track of a single concurrent task starting and finishing;
@@ -38,25 +39,25 @@
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
*/
- public TaskSingleDrainer(Handler handler, DrainListener listener) {
- mTaskDrainer = new TaskDrainer<>(handler, listener);
+ public TaskSingleDrainer(Executor executor, DrainListener listener) {
+ mTaskDrainer = new TaskDrainer<>(executor, listener);
}
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
* @param name an optional name used for debug logging
*/
- public TaskSingleDrainer(Handler handler, DrainListener listener, String name) {
- mTaskDrainer = new TaskDrainer<>(handler, listener, name);
+ public TaskSingleDrainer(Executor executor, DrainListener listener, String name) {
+ mTaskDrainer = new TaskDrainer<>(executor, listener, name);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 36d5615..e81fbee 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -28,7 +28,6 @@
import android.graphics.Point;
import android.media.projection.MediaProjection;
import android.os.Handler;
-import android.os.UserHandle;
import android.util.SparseArray;
import android.view.Display;
import android.view.Surface;
@@ -636,6 +635,8 @@
*
* @hide until we make it a system api
*/
+ @SystemApi
+ @TestApi
@RequiresPermission(Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS)
public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() {
return mGlobal.getAmbientBrightnessStats();
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 9e0c680..97868fa 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -26,8 +26,6 @@
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.PointerIcon;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
/** @hide */
interface IInputManager {
@@ -67,11 +65,6 @@
String keyboardLayoutDescriptor);
void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor);
- KeyboardLayout getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
- void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
- String keyboardLayoutDescriptor);
// Registers an input devices changed listener.
void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index fdea5a2..6ae7a14 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,7 +17,6 @@
package android.hardware.input;
import android.annotation.IntDef;
-import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
@@ -43,8 +42,6 @@
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.os.SomeArgs;
@@ -703,52 +700,6 @@
}
}
-
- /**
- * Gets the keyboard layout for the specified input device and IME subtype.
- *
- * @param identifier The identifier for the input device.
- * @param inputMethodInfo The input method.
- * @param inputMethodSubtype The input method subtype. {@code null} if this input method does
- * not support any subtype.
- *
- * @return The associated {@link KeyboardLayout}, or null if one has not been set.
- *
- * @hide
- */
- @Nullable
- public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) {
- try {
- return mIm.getKeyboardLayoutForInputDevice(
- identifier, inputMethodInfo, inputMethodSubtype);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /**
- * Sets the keyboard layout for the specified input device and IME subtype pair.
- *
- * @param identifier The identifier for the input device.
- * @param inputMethodInfo The input method with which to associate the keyboard layout.
- * @param inputMethodSubtype The input method subtype which which to associate the keyboard
- * layout. {@code null} if this input method does not support any subtype.
- * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
- *
- * @hide
- */
- public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype,
- String keyboardLayoutDescriptor) {
- try {
- mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
- inputMethodSubtype, keyboardLayoutDescriptor);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
/**
* Gets the TouchCalibration applied to the specified input device's coordinates.
*
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 4ea0f55..eb7ea67 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -16,11 +16,8 @@
package android.hardware.input;
-import android.annotation.Nullable;
import android.hardware.display.DisplayViewport;
import android.view.InputEvent;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
import java.util.List;
@@ -46,16 +43,6 @@
public abstract void setInteractive(boolean interactive);
/**
- * Notifies that InputMethodManagerService switched the current input method subtype.
- *
- * @param userId user id that indicates who is using the specified input method and subtype.
- * @param inputMethodInfo {@code null} when no input method is selected.
- * @param subtype {@code null} when {@code inputMethodInfo} does has no subtype.
- */
- public abstract void onInputMethodSubtypeChanged(int userId,
- @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype);
-
- /**
* Toggles Caps Lock state for input device with specific id.
*
* @param deviceId The id of input device.
diff --git a/core/java/android/hardware/input/TouchCalibration.java b/core/java/android/hardware/input/TouchCalibration.java
index 15503ed..025fad0 100644
--- a/core/java/android/hardware/input/TouchCalibration.java
+++ b/core/java/android/hardware/input/TouchCalibration.java
@@ -123,10 +123,4 @@
Float.floatToIntBits(mYScale) ^
Float.floatToIntBits(mYOffset);
}
-
- @Override
- public String toString() {
- return String.format("[%f, %f, %f, %f, %f, %f]",
- mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset);
- }
}
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 0294a29..2a878eb 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -441,6 +441,15 @@
*/
public static @NonNull ProgramSelector createAmFmSelector(
@RadioManager.Band int band, int frequencyKhz, int subChannel) {
+ if (band == RadioManager.BAND_INVALID) {
+ // 50MHz is a rough boundary between AM (<30MHz) and FM (>60MHz).
+ if (frequencyKhz < 50000) {
+ band = (subChannel <= 0) ? RadioManager.BAND_AM : RadioManager.BAND_AM_HD;
+ } else {
+ band = (subChannel <= 0) ? RadioManager.BAND_FM : RadioManager.BAND_FM_HD;
+ }
+ }
+
boolean isAm = (band == RadioManager.BAND_AM || band == RadioManager.BAND_AM_HD);
boolean isDigital = (band == RadioManager.BAND_AM_HD || band == RadioManager.BAND_FM_HD);
if (!isAm && !isDigital && band != RadioManager.BAND_FM) {
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index 3cc4b56..6e51060 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -96,6 +96,48 @@
*/
public static final String METADATA_KEY_CLOCK = "android.hardware.radio.metadata.CLOCK";
+ /**
+ * Technology-independent program name (station name).
+ */
+ public static final String METADATA_KEY_PROGRAM_NAME =
+ "android.hardware.radio.metadata.PROGRAM_NAME";
+
+ /**
+ * DAB ensemble name.
+ */
+ public static final String METADATA_KEY_DAB_ENSEMBLE_NAME =
+ "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME";
+
+ /**
+ * DAB ensemble name - short version (up to 8 characters).
+ */
+ public static final String METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT =
+ "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME_SHORT";
+
+ /**
+ * DAB service name.
+ */
+ public static final String METADATA_KEY_DAB_SERVICE_NAME =
+ "android.hardware.radio.metadata.DAB_SERVICE_NAME";
+
+ /**
+ * DAB service name - short version (up to 8 characters).
+ */
+ public static final String METADATA_KEY_DAB_SERVICE_NAME_SHORT =
+ "android.hardware.radio.metadata.DAB_SERVICE_NAME_SHORT";
+
+ /**
+ * DAB component name.
+ */
+ public static final String METADATA_KEY_DAB_COMPONENT_NAME =
+ "android.hardware.radio.metadata.DAB_COMPONENT_NAME";
+
+ /**
+ * DAB component name.
+ */
+ public static final String METADATA_KEY_DAB_COMPONENT_NAME_SHORT =
+ "android.hardware.radio.metadata.DAB_COMPONENT_NAME_SHORT";
+
private static final int METADATA_TYPE_INVALID = -1;
private static final int METADATA_TYPE_INT = 0;
@@ -119,6 +161,13 @@
METADATA_KEYS_TYPE.put(METADATA_KEY_ICON, METADATA_TYPE_BITMAP);
METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
METADATA_KEYS_TYPE.put(METADATA_KEY_CLOCK, METADATA_TYPE_CLOCK);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_PROGRAM_NAME, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_DAB_ENSEMBLE_NAME, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_DAB_SERVICE_NAME, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_DAB_SERVICE_NAME_SHORT, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_DAB_COMPONENT_NAME, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_DAB_COMPONENT_NAME_SHORT, METADATA_TYPE_TEXT);
}
// keep in sync with: system/media/radio/include/system/radio_metadata.h
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f38c37a..b3bf092 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1081,7 +1081,7 @@
* @return true if the current input method and subtype was successfully switched to the last
* used input method and subtype.
*/
- public boolean switchToPreviousInputMethod() {
+ public final boolean switchToPreviousInputMethod() {
return mImm.switchToPreviousInputMethodInternal(mToken);
}
@@ -1093,7 +1093,7 @@
* @return true if the current input method and subtype was successfully switched to the next
* input method and subtype.
*/
- public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
+ public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
}
@@ -1106,7 +1106,7 @@
* and subtype in order to provide the consistent user experience in switching
* between IMEs and subtypes.
*/
- public boolean shouldOfferSwitchingToNextInputMethod() {
+ public final boolean shouldOfferSwitchingToNextInputMethod() {
return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
}
@@ -1450,7 +1450,7 @@
* @param id Unique identifier of the new input method to start.
* @param subtype The new subtype of the new input method to be switched to.
*/
- public void switchInputMethod(String id, InputMethodSubtype subtype) {
+ public final void switchInputMethod(String id, InputMethodSubtype subtype) {
mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
}
@@ -2059,7 +2059,7 @@
* @see InputMethodManager#SHOW_FORCED
* @param flags Provides additional operating flags.
*/
- public void requestShowSelf(int flags) {
+ public final void requestShowSelf(int flags) {
mImm.showSoftInputFromInputMethodInternal(mToken, flags);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 71266a0..36f359b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -453,133 +453,177 @@
public static final int TYPE_NONE = -1;
/**
- * The Mobile data connection. When active, all data traffic
- * will use this network type's interface by default
- * (it has a default route)
+ * A Mobile data connection. Devices may support more than one.
+ *
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+ * appropriate network. {@see NetworkCapabilities} for supported transports.
*/
+ @Deprecated
public static final int TYPE_MOBILE = 0;
+
/**
- * The WIFI data connection. When active, all data traffic
- * will use this network type's interface by default
- * (it has a default route).
+ * A WIFI data connection. Devices may support more than one.
+ *
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+ * appropriate network. {@see NetworkCapabilities} for supported transports.
*/
+ @Deprecated
public static final int TYPE_WIFI = 1;
+
/**
* An MMS-specific Mobile data connection. This network type may use the
* same network interface as {@link #TYPE_MOBILE} or it may use a different
* one. This is used by applications needing to talk to the carrier's
* Multimedia Messaging Service servers.
*
- * @deprecated Applications should instead use
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
* {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
* provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability.
*/
@Deprecated
public static final int TYPE_MOBILE_MMS = 2;
+
/**
* A SUPL-specific Mobile data connection. This network type may use the
* same network interface as {@link #TYPE_MOBILE} or it may use a different
* one. This is used by applications needing to talk to the carrier's
* Secure User Plane Location servers for help locating the device.
*
- * @deprecated Applications should instead use
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
* {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
* provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability.
*/
@Deprecated
public static final int TYPE_MOBILE_SUPL = 3;
+
/**
* A DUN-specific Mobile data connection. This network type may use the
* same network interface as {@link #TYPE_MOBILE} or it may use a different
* one. This is sometimes by the system when setting up an upstream connection
* for tethering so that the carrier is aware of DUN traffic.
+ *
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
+ * provides the {@link NetworkCapabilities#NET_CAPABILITY_DUN} capability.
*/
+ @Deprecated
public static final int TYPE_MOBILE_DUN = 4;
+
/**
* A High Priority Mobile data connection. This network type uses the
* same network interface as {@link #TYPE_MOBILE} but the routing setup
* is different.
*
- * @deprecated Applications should instead use
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
- * uses the {@link NetworkCapabilities#TRANSPORT_CELLULAR} transport.
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+ * appropriate network. {@see NetworkCapabilities} for supported transports.
*/
@Deprecated
public static final int TYPE_MOBILE_HIPRI = 5;
+
/**
- * The WiMAX data connection. When active, all data traffic
- * will use this network type's interface by default
- * (it has a default route).
+ * A WiMAX data connection.
+ *
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+ * appropriate network. {@see NetworkCapabilities} for supported transports.
*/
+ @Deprecated
public static final int TYPE_WIMAX = 6;
/**
- * The Bluetooth data connection. When active, all data traffic
- * will use this network type's interface by default
- * (it has a default route).
+ * A Bluetooth data connection.
+ *
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+ * appropriate network. {@see NetworkCapabilities} for supported transports.
*/
+ @Deprecated
public static final int TYPE_BLUETOOTH = 7;
/**
* Dummy data connection. This should not be used on shipping devices.
+ * @deprecated This is not used any more.
*/
+ @Deprecated
public static final int TYPE_DUMMY = 8;
/**
- * The Ethernet data connection. When active, all data traffic
- * will use this network type's interface by default
- * (it has a default route).
+ * An Ethernet data connection.
+ *
+ * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
+ * appropriate network. {@see NetworkCapabilities} for supported transports.
*/
+ @Deprecated
public static final int TYPE_ETHERNET = 9;
/**
* Over the air Administration.
+ * @deprecated Use {@link NetworkCapabilities} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_MOBILE_FOTA = 10;
/**
* IP Multimedia Subsystem.
+ * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IMS} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_MOBILE_IMS = 11;
/**
* Carrier Branded Services.
+ * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_CBS} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_MOBILE_CBS = 12;
/**
* A Wi-Fi p2p connection. Only requesting processes will have access to
* the peers connected.
+ * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_WIFI_P2P} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_WIFI_P2P = 13;
/**
* The network to use for initially attaching to the network
+ * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IA} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_MOBILE_IA = 14;
/**
* Emergency PDN connection for emergency services. This
* may include IMS and MMS in emergency situations.
+ * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_EIMS} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_MOBILE_EMERGENCY = 15;
/**
* The network that uses proxy to achieve connectivity.
+ * @deprecated Use {@link NetworkCapabilities} instead.
* {@hide}
*/
+ @Deprecated
public static final int TYPE_PROXY = 16;
/**
* A virtual network using one or more native bearers.
* It may or may not be providing security services.
+ * @deprecated Applications should use {@link NetworkCapabilities#TRANSPORT_VPN} instead.
*/
+ @Deprecated
public static final int TYPE_VPN = 17;
/** {@hide} */
@@ -686,8 +730,10 @@
* @param type the type needing naming
* @return a String for the given type, or a string version of the type ("87")
* if no name is known.
+ * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
* {@hide}
*/
+ @Deprecated
public static String getNetworkTypeName(int type) {
switch (type) {
case TYPE_NONE:
@@ -738,8 +784,10 @@
* This should be replaced in the future by a network property.
* @param networkType the type to check
* @return a boolean - {@code true} if uses cellular network, else {@code false}
+ * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
* {@hide}
*/
+ @Deprecated
public static boolean isNetworkTypeMobile(int networkType) {
switch (networkType) {
case TYPE_MOBILE:
@@ -761,8 +809,10 @@
/**
* Checks if the given network type is backed by a Wi-Fi radio.
*
+ * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
* @hide
*/
+ @Deprecated
public static boolean isNetworkTypeWifi(int networkType) {
switch (networkType) {
case TYPE_WIFI:
@@ -1529,6 +1579,8 @@
* IllegalArgumentException if no mapping from the legacy type to
* NetworkCapabilities is known.
*
+ * @deprecated Types are deprecated. Use {@link NetworkCallback} or {@link NetworkRequest}
+ * to find the network instead.
* @hide
*/
public static NetworkCapabilities networkCapabilitiesForType(int type) {
@@ -2380,6 +2432,7 @@
*
* @param networkType The type of network you want to report on
* @param percentage The quality of the connection 0 is bad, 100 is good
+ * @deprecated Types are deprecated. Use {@link #reportNetworkConnectivity} instead.
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
@@ -2511,9 +2564,10 @@
*
* @param networkType The network type we'd like to check
* @return {@code true} if supported, else {@code false}
- *
+ * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
* @hide
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public boolean isNetworkSupported(int networkType) {
try {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index e6ad89a..999771a 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -38,14 +38,18 @@
* <table>
* <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr>
* <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr>
- * <tr><td><code>SCANNING</code></td><td><code>CONNECTING</code></td></tr>
+ * <tr><td><code>SCANNING</code></td><td><code>DISCONNECTED</code></td></tr>
* <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
* <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
+ * <tr><td><code>OBTAINING_IPADDR</code></td><td><code>CONNECTING</code></td></tr>
+ * <tr><td><code>VERIFYING_POOR_LINK</code></td><td><code>CONNECTING</code></td></tr>
+ * <tr><td><code>CAPTIVE_PORTAL_CHECK</code></td><td><code>CONNECTING</code></td></tr>
* <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
+ * <tr><td><code>SUSPENDED</code></td><td><code>SUSPENDED</code></td></tr>
* <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
* <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
- * <tr><td><code>UNAVAILABLE</code></td><td><code>DISCONNECTED</code></td></tr>
* <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
+ * <tr><td><code>BLOCKED</code></td><td><code>DISCONNECTED</code></td></tr>
* </table>
*/
public enum State {
@@ -163,8 +167,17 @@
* @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
* ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
* ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
- * types defined by {@link ConnectivityManager}
+ * types defined by {@link ConnectivityManager}.
+ * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
+ * instead with one of the NetworkCapabilities#TRANSPORT_* constants :
+ * {@link #getType} and {@link #getTypeName} cannot account for networks using
+ * multiple transports. Note that generally apps should not care about transport;
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
+ * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
+ * apps concerned with meteredness or bandwidth should be looking at, as they
+ * offer this information with much better accuracy.
*/
+ @Deprecated
public int getType() {
synchronized (this) {
return mNetworkType;
@@ -172,8 +185,10 @@
}
/**
+ * @deprecated Use {@link NetworkCapabilities} instead
* @hide
*/
+ @Deprecated
public void setType(int type) {
synchronized (this) {
mNetworkType = type;
@@ -205,7 +220,16 @@
* Return a human-readable name describe the type of the network,
* for example "WIFI" or "MOBILE".
* @return the name of the network type
+ * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
+ * instead with one of the NetworkCapabilities#TRANSPORT_* constants :
+ * {@link #getType} and {@link #getTypeName} cannot account for networks using
+ * multiple transports. Note that generally apps should not care about transport;
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
+ * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
+ * apps concerned with meteredness or bandwidth should be looking at, as they
+ * offer this information with much better accuracy.
*/
+ @Deprecated
public String getTypeName() {
synchronized (this) {
return mTypeName;
@@ -230,7 +254,15 @@
* that the network is fully usable.
* @return {@code true} if network connectivity exists or is in the process
* of being established, {@code false} otherwise.
+ * @deprecated Apps should instead use the
+ * {@link android.net.ConnectivityManager.NetworkCallback} API to
+ * learn about connectivity changes.
+ * {@link ConnectivityManager#registerDefaultNetworkCallback} and
+ * {@link ConnectivityManager#registerNetworkCallback}. These will
+ * give a more accurate picture of the connectivity state of
+ * the device and let apps react more easily and quickly to changes.
*/
+ @Deprecated
public boolean isConnectedOrConnecting() {
synchronized (this) {
return mState == State.CONNECTED || mState == State.CONNECTING;
@@ -259,8 +291,18 @@
* data roaming has been disabled.</li>
* <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
* </ul>
+ * Since Android L, this always returns {@code true}, because the system only
+ * returns info for available networks.
* @return {@code true} if the network is available, {@code false} otherwise
+ * @deprecated Apps should instead use the
+ * {@link android.net.ConnectivityManager.NetworkCallback} API to
+ * learn about connectivity changes.
+ * {@link ConnectivityManager#registerDefaultNetworkCallback} and
+ * {@link ConnectivityManager#registerNetworkCallback}. These will
+ * give a more accurate picture of the connectivity state of
+ * the device and let apps react more easily and quickly to changes.
*/
+ @Deprecated
public boolean isAvailable() {
synchronized (this) {
return mIsAvailable;
@@ -270,9 +312,11 @@
/**
* Sets if the network is available, ie, if the connectivity is possible.
* @param isAvailable the new availability value.
+ * @deprecated Use {@link NetworkCapabilities} instead
*
* @hide
*/
+ @Deprecated
public void setIsAvailable(boolean isAvailable) {
synchronized (this) {
mIsAvailable = isAvailable;
@@ -285,7 +329,10 @@
* network following a disconnect from another network.
* @return {@code true} if this is a failover attempt, {@code false}
* otherwise.
+ * @deprecated This field is not populated in recent Android releases,
+ * and does not make a lot of sense in a multi-network world.
*/
+ @Deprecated
public boolean isFailover() {
synchronized (this) {
return mIsFailover;
@@ -296,8 +343,10 @@
* Set the failover boolean.
* @param isFailover {@code true} to mark the current connection attempt
* as a failover.
+ * @deprecated This hasn't been set in any recent Android release.
* @hide
*/
+ @Deprecated
public void setFailover(boolean isFailover) {
synchronized (this) {
mIsFailover = isFailover;
@@ -322,7 +371,10 @@
}
}
- /** {@hide} */
+ /**
+ * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead.
+ * {@hide}
+ */
@VisibleForTesting
@Deprecated
public void setRoaming(boolean isRoaming) {
@@ -334,7 +386,15 @@
/**
* Reports the current coarse-grained state of the network.
* @return the coarse-grained state
+ * @deprecated Apps should instead use the
+ * {@link android.net.ConnectivityManager.NetworkCallback} API to
+ * learn about connectivity changes.
+ * {@link ConnectivityManager#registerDefaultNetworkCallback} and
+ * {@link ConnectivityManager#registerNetworkCallback}. These will
+ * give a more accurate picture of the connectivity state of
+ * the device and let apps react more easily and quickly to changes.
*/
+ @Deprecated
public State getState() {
synchronized (this) {
return mState;
@@ -358,8 +418,10 @@
* if one was supplied. May be {@code null}.
* @param extraInfo an optional {@code String} providing addditional network state
* information passed up from the lower networking layers.
+ * @deprecated Use {@link NetworkCapabilities} instead.
* @hide
*/
+ @Deprecated
public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
synchronized (this) {
this.mDetailedState = detailedState;
@@ -385,6 +447,8 @@
* Report the reason an attempt to establish connectivity failed,
* if one is available.
* @return the reason for failure, or null if not available
+ * @deprecated This method does not have a consistent contract that could make it useful
+ * to callers.
*/
public String getReason() {
synchronized (this) {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 8b4f02e..6363161 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.content.Intent;
@@ -138,6 +139,23 @@
*/
public static final String EXTRA_SEQUENCE = "seq";
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}:
+ * Contains list of Bundles representing battery events
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_EVENTS = "android.os.extra.EVENTS";
+
+ /**
+ * Extra for event in {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}:
+ * Long value representing time when event occurred as returned by
+ * {@link android.os.SystemClock#elapsedRealtime()}
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
+
// values for "status" field in the ACTION_BATTERY_CHANGED Intent
public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;
public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 29c298e..402c995 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -74,6 +74,7 @@
*/
oneway void sendSubscriberBroadcast(in IBinder intentSender, long configUid, long configId,
long subscriptionId, long subscriptionRuleId,
+ in String[] cookies,
in StatsDimensionsValue dimensionsValue);
/** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index c7d89b0..2cb5aee 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -141,6 +141,14 @@
public abstract void setDozeOverrideFromDreamManager(
int screenState, int screenBrightness);
+ /**
+ * Used by sidekick manager to tell the power manager if it shouldn't change the display state
+ * when a draw wake lock is acquired. Some processes may grab such a wake lock to do some work
+ * in a powered-up state, but we shouldn't give up sidekick control over the display until this
+ * override is lifted.
+ */
+ public abstract void setDrawWakeLockOverrideFromSidekick(boolean keepState);
+
public abstract PowerSaveState getLowPowerState(int serviceType);
public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index fb11d00..8aef012 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -228,6 +228,25 @@
/** @hide */
public static final String RES_CAN_BLOCK_NUMBERS = "can_block";
+ /** @hide */
+ public static final String RES_ENHANCED_SETTING_IS_ENABLED = "enhanced_setting_enabled";
+
+ /** @hide */
+ public static final String RES_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "show_emergency_call_notification";
+
+ /** @hide */
+ public static final String EXTRA_ENHANCED_SETTING_KEY = "extra_enhanced_setting_key";
+
+ /** @hide */
+ public static final String EXTRA_ENHANCED_SETTING_VALUE = "extra_enhanced_setting_value";
+
+ /** @hide */
+ public static final String EXTRA_CONTACT_EXIST = "extra_contact_exist";
+
+ /** @hide */
+ public static final String EXTRA_CALL_PRESENTATION = "extra_call_presentation";
+
/**
* Returns whether a given number is in the blocked list.
*
@@ -314,11 +333,33 @@
public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
"get_block_suppression_status";
+ public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "should_show_emergency_call_notification";
+
public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
"blocking_suppressed_until_timestamp";
+ public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
+ public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
+
+ /* Preference key of block numbers not in contacts setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED =
+ "block_numbers_not_in_contacts_setting";
+ /* Preference key of block private number calls setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_PRIVATE =
+ "block_private_number_calls_setting";
+ /* Preference key of block payphone calls setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_PAYPHONE =
+ "block_payphone_calls_setting";
+ /* Preference key of block unknown calls setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_UNKNOWN =
+ "block_unknown_calls_setting";
+ /* Preference key for whether should show an emergency call notification. */
+ public static final String ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "show_emergency_call_notification";
+
/**
* Notifies the provider that emergency services were contacted by the user.
* <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
@@ -342,13 +383,19 @@
/**
* Returns {@code true} if {@code phoneNumber} is blocked taking
- * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have
- * not been contacted recently, this method is equivalent to
- * {@link #isBlocked(Context, String)}.
+ * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services
+ * have not been contacted recently and enhanced call blocking not been enabled, this
+ * method is equivalent to {@link #isBlocked(Context, String)}.
+ *
+ * @param context the context of the caller.
+ * @param phoneNumber the number to check.
+ * @param extras the extra attribute of the number.
+ * @return {@code true} if should block the number. {@code false} otherwise.
*/
- public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
+ public static boolean shouldSystemBlockNumber(Context context, String phoneNumber,
+ Bundle extras) {
final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
+ AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras);
return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
}
@@ -363,9 +410,62 @@
}
/**
- * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
- * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
- * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+ * Check whether should show the emergency call notification.
+ *
+ * @param context the context of the caller.
+ * @return {@code true} if should show emergency call notification. {@code false} otherwise.
+ */
+ public static boolean shouldShowEmergencyCallNotification(Context context) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null);
+ return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false);
+ }
+
+ /**
+ * Check whether the enhanced block setting is enabled.
+ *
+ * @param context the context of the caller.
+ * @param key the key of the setting to check, can be
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+ * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
+ * @return {@code true} if the setting is enabled. {@code false} otherwise.
+ */
+ public static boolean getEnhancedBlockSetting(Context context, String key) {
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras);
+ return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false);
+ }
+
+ /**
+ * Set the enhanced block setting enabled status.
+ *
+ * @param context the context of the caller.
+ * @param key the key of the setting to set, can be
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+ * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
+ * @param value the enabled statue of the setting to set.
+ */
+ public static void setEnhancedBlockSetting(Context context, String key, boolean value) {
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
+ extras.putBoolean(EXTRA_ENHANCED_SETTING_VALUE, value);
+ context.getContentResolver().call(AUTHORITY_URI, METHOD_SET_ENHANCED_BLOCK_SETTING,
+ null, extras);
+ }
+
+ /**
+ * Represents the current status of
+ * {@link #shouldSystemBlockNumber(Context, String, Bundle)}. If emergency services
+ * have been contacted recently, {@link #isSuppressed} is {@code true}, and blocking
+ * is disabled until the timestamp {@link #untilTimestampMillis}.
*/
public static class BlockSuppressionStatus {
public final boolean isSuppressed;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index d9808a3..1da6602 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -692,8 +692,8 @@
// Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
// If the magic is non-zero, we simply return thumbnail if it does exist.
// querying MediaProvider and simply return thumbnail.
- MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
- : Images.Media.EXTERNAL_CONTENT_URI);
+ MiniThumbFile thumbFile = MiniThumbFile.instance(
+ isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI);
Cursor c = null;
try {
long magic = thumbFile.getMagic(origId);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bd29d2d..e0a1b3e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -430,6 +430,20 @@
"android.settings.WIFI_IP_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of data and view data usage.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_DATA_USAGE_SETTINGS =
+ "android.settings.DATA_USAGE_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of Bluetooth.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -6170,10 +6184,13 @@
/**
* Integer property that specifies the type of color space adjustment to
- * perform. Valid values are defined in AccessibilityManager:
+ * perform. Valid values are defined in AccessibilityManager and Settings arrays.xml:
* - AccessibilityManager.DALTONIZER_DISABLED = -1
* - AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY = 0
- * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY = 12
+ * - <item>@string/daltonizer_mode_protanomaly</item> = 11
+ * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY and
+ * <item>@string/daltonizer_mode_deuteranomaly</item> = 12
+ * - <item>@string/daltonizer_mode_tritanomaly</item> = 13
*
* @hide
*/
@@ -6181,7 +6198,8 @@
"accessibility_display_daltonizer";
private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR =
- new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "12"});
+ new SettingsValidators.DiscreteValueValidator(
+ new String[] {"-1", "0", "11", "12", "13"});
/**
* Setting that specifies whether automatic click when the mouse pointer stops moving is
@@ -10897,6 +10915,15 @@
private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
+
+ /**
+ * The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting is not set
+ * or the value is 0, the default max will be used.
+ *
+ * @hide
+ */
+ public static final String LOW_POWER_MODE_TRIGGER_LEVEL_MAX = "low_power_trigger_level_max";
+
/**
* If not 0, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
@@ -11483,7 +11510,14 @@
/**
* The packages whitelisted to be run in autofill compatibility mode. The list
- * of packages is ":" colon delimited.
+ * of packages is {@code ":"} colon delimited, and each entry has the name of the
+ * package and an optional list of url bar resource ids (the list is delimited by
+ * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
+ *
+ * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
+ * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
+ * have 2 ids {@code url_foo} and {@code url_bas}) would be
+ * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
*
* @hide
*/
@@ -11573,6 +11607,8 @@
VALIDATORS.put(DOCK_AUDIO_MEDIA_ENABLED, DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR);
VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
+ VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
+ LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR);
VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR);
VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR);
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 70c4ec0..de23455 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -32,7 +32,6 @@
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Pair;
import android.util.Xml;
import com.android.internal.R;
@@ -79,7 +78,7 @@
private final String mSettingsActivity;
@Nullable
- private final ArrayMap<String, Pair<Long, String>> mCompatibilityPackages;
+ private final ArrayMap<String, Long> mCompatibilityPackages;
public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
@@ -117,7 +116,7 @@
}
String settingsActivity = null;
- ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
+ ArrayMap<String, Long> compatibilityPackages = null;
try {
final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -153,10 +152,9 @@
mCompatibilityPackages = compatibilityPackages;
}
- private ArrayMap<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
- Resources resources)
- throws IOException, XmlPullParserException {
- ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
+ private ArrayMap<String, Long> parseCompatibilityPackages(XmlPullParser parser,
+ Resources resources) throws IOException, XmlPullParserException {
+ ArrayMap<String, Long> compatibilityPackages = null;
final int outerDepth = parser.getDepth();
int type;
@@ -200,13 +198,18 @@
} else {
maxVersionCode = Long.MAX_VALUE;
}
- final String urlBarResourceId = cpAttributes.getString(
- R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
+ if (true) { // TODO(b/74445943): remove block after P DP2 is branched
+ final String urlBarResourceId = cpAttributes.getString(
+ R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
+ if (urlBarResourceId != null) {
+ Log.e(TAG, "Service is using deprecated attribute 'urlBarResourceId'");
+ }
+ }
if (compatibilityPackages == null) {
compatibilityPackages = new ArrayMap<>();
}
- compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId));
+ compatibilityPackages.put(name, maxVersionCode);
} finally {
XmlUtils.skipCurrentTag(parser);
if (cpAttributes != null) {
@@ -228,23 +231,10 @@
return mSettingsActivity;
}
- public ArrayMap<String, Pair<Long, String>> getCompatibilityPackages() {
+ public ArrayMap<String, Long> getCompatibilityPackages() {
return mCompatibilityPackages;
}
- /**
- * Gets the resource id of the URL bar for a package. Used in compat mode
- */
- // TODO: return a list of strings instead
- @Nullable
- public String getUrlBarResourceId(String packageName) {
- if (mCompatibilityPackages == null) {
- return null;
- }
- final Pair<Long, String> pair = mCompatibilityPackages.get(packageName);
- return pair == null ? null : pair.second;
- }
-
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index eebd22a..ea10ae7 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -149,13 +149,19 @@
/**
* Whether notification suppressed by DND should not interruption visually when the screen is
* off.
+ *
+ * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_OFF =
NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
/**
* Whether notification suppressed by DND should not interruption visually when the screen is
* on.
+ *
+ * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}.
*/
+ @Deprecated
public static final int SUPPRESSED_EFFECT_SCREEN_ON =
NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
@@ -1453,7 +1459,8 @@
/**
* Returns the type(s) of visual effects that should be suppressed for this notification.
- * See {@link #SUPPRESSED_EFFECT_SCREEN_OFF}, {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
+ * See {@link NotificationManager.Policy}, e.g.
+ * {@link NotificationManager.Policy#SUPPRESSED_EFFECT_LIGHTS}.
*/
public int getSuppressedVisualEffects() {
return mSuppressedVisualEffects;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index b61919e..740a387 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -92,10 +92,12 @@
private static final boolean DEFAULT_ALLOW_REMINDERS = false;
private static final boolean DEFAULT_ALLOW_EVENTS = false;
private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
- private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
- private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
+ private static final boolean DEFAULT_ALLOW_SCREEN_OFF = false;
+ private static final boolean DEFAULT_ALLOW_SCREEN_ON = false;
+ private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
+ Policy.getAllSuppressedVisualEffects();
- public static final int XML_VERSION = 4;
+ public static final int XML_VERSION = 5;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -113,6 +115,8 @@
private static final String ALLOW_ATT_EVENTS = "events";
private static final String ALLOW_ATT_SCREEN_OFF = "visualScreenOff";
private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn";
+ private static final String DISALLOW_TAG = "disallow";
+ private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects";
private static final String CONDITION_ATT_ID = "id";
private static final String CONDITION_ATT_SUMMARY = "summary";
@@ -146,6 +150,7 @@
public int allowCallsFrom = DEFAULT_SOURCE;
public int allowMessagesFrom = DEFAULT_SOURCE;
public int user = UserHandle.USER_SYSTEM;
+ public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
public int version;
@@ -180,6 +185,7 @@
allowAlarms = source.readInt() == 1;
allowMedia = source.readInt() == 1;
allowSystem = source.readInt() == 1;
+ suppressedVisualEffects = source.readInt();
}
@Override
@@ -212,6 +218,7 @@
dest.writeInt(allowAlarms ? 1 : 0);
dest.writeInt(allowMedia ? 1 : 0);
dest.writeInt(allowSystem ? 1 : 0);
+ dest.writeInt(suppressedVisualEffects);
}
@Override
@@ -230,6 +237,7 @@
.append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
.append(",allowWhenScreenOff=").append(allowWhenScreenOff)
.append(",allowWhenScreenOn=").append(allowWhenScreenOn)
+ .append(",suppressedVisualEffects=").append(suppressedVisualEffects)
.append(",automaticRules=").append(automaticRules)
.append(",manualRule=").append(manualRule)
.append(']').toString();
@@ -279,6 +287,10 @@
if (allowWhenScreenOn != to.allowWhenScreenOn) {
d.addLine("allowWhenScreenOn", allowWhenScreenOn, to.allowWhenScreenOn);
}
+ if (suppressedVisualEffects != to.suppressedVisualEffects) {
+ d.addLine("suppressedVisualEffects", suppressedVisualEffects,
+ to.suppressedVisualEffects);
+ }
final ArraySet<String> allRules = new ArraySet<>();
addKeys(allRules, automaticRules);
addKeys(allRules, to.automaticRules);
@@ -383,7 +395,8 @@
&& other.allowWhenScreenOn == allowWhenScreenOn
&& other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
- && Objects.equals(other.manualRule, manualRule);
+ && Objects.equals(other.manualRule, manualRule)
+ && other.suppressedVisualEffects == suppressedVisualEffects;
}
@Override
@@ -391,7 +404,8 @@
return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
allowRepeatCallers, allowMessages,
allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
- allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule);
+ allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule,
+ suppressedVisualEffects);
}
private static String toDayList(int[] days) {
@@ -474,6 +488,8 @@
rt.allowCallsFrom = DEFAULT_SOURCE;
rt.allowMessagesFrom = DEFAULT_SOURCE;
}
+ // continue to read even though we now have suppressedVisualEffects, in case
+ // we need to revert to users' previous settings
rt.allowWhenScreenOff =
safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
rt.allowWhenScreenOn =
@@ -482,6 +498,9 @@
rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
DEFAULT_ALLOW_MEDIA);
rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
+ } else if (DISALLOW_TAG.equals(tag)) {
+ rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS,
+ DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
} else if (AUTOMATIC_TAG.equals(tag)) {
@@ -517,6 +536,10 @@
out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
out.endTag(null, ALLOW_TAG);
+ out.startTag(null, DISALLOW_TAG);
+ out.attribute(null, DISALLOW_ATT_VISUAL_EFFECTS, Integer.toString(suppressedVisualEffects));
+ out.endTag(null, DISALLOW_TAG);
+
if (manualRule != null) {
out.startTag(null, MANUAL_TAG);
writeRuleXml(manualRule, out);
@@ -701,13 +724,6 @@
if (allowRepeatCallers) {
priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
}
- int suppressedVisualEffects = 0;
- if (!allowWhenScreenOff) {
- suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
- }
- if (!allowWhenScreenOn) {
- suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
- }
if (allowAlarms) {
priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
}
@@ -770,10 +786,7 @@
allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders,
allowMessagesFrom);
if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
- allowWhenScreenOff =
- (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_OFF) == 0;
- allowWhenScreenOn =
- (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
+ suppressedVisualEffects = policy.suppressedVisualEffects;
}
}
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 2c8c4ec..57c8def 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -34,6 +34,7 @@
import android.text.TextUtils;
import android.util.Slog;
import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
@@ -47,7 +48,7 @@
* {@link android.view.textclassifier.TextClassifierImpl} is loaded in the calling app's process.
*
* <p>See: {@link TextClassifier}.
- * See: {@link android.view.textclassifier.TextClassificationManager}.
+ * See: {@link TextClassificationManager}.
*
* <p>Include the following in the manifest:
*
@@ -237,6 +238,18 @@
@NonNull Callback<TextLinks> callback);
/**
+ * Returns a TextClassifier that runs in this service's process.
+ * If the local TextClassifier is disabled, this returns {@link TextClassifier#NO_OP}.
+ */
+ public final TextClassifier getLocalTextClassifier() {
+ final TextClassificationManager tcm = getSystemService(TextClassificationManager.class);
+ if (tcm != null) {
+ return tcm.getTextClassifier(TextClassifier.LOCAL);
+ }
+ return TextClassifier.NO_OP;
+ }
+
+ /**
* Callbacks for TextClassifierService results.
*
* @param <T> the type of the result
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 8588df7..a132730 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -788,8 +788,8 @@
com.android.internal.R.style.Animation_Wallpaper;
mInputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
- Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets, mOutsets,
- mDisplayCutout, mInputChannel) < 0) {
+ Display.DEFAULT_DISPLAY, mWinFrame, mContentInsets, mStableInsets,
+ mOutsets, mDisplayCutout, mInputChannel) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index c211e2d..b740193 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -211,7 +211,8 @@
return mHyphenationFrequency;
}
- private boolean isSameTextMetricsInternal(@NonNull TextPaint paint,
+ /** @hide */
+ public boolean isSameTextMetricsInternal(@NonNull TextPaint paint,
@NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy,
@Layout.HyphenationFrequency int frequency) {
return mTextDir == textDir
@@ -247,6 +248,23 @@
mPaint.getFontVariationSettings(), mPaint.isElegantTextHeight(), mTextDir,
mBreakStrategy, mHyphenationFrequency);
}
+
+ @Override
+ public String toString() {
+ return "{"
+ + "textSize=" + mPaint.getTextSize()
+ + ", textScaleX=" + mPaint.getTextScaleX()
+ + ", textSkewX=" + mPaint.getTextSkewX()
+ + ", letterSpacing=" + mPaint.getLetterSpacing()
+ + ", textLocale=" + mPaint.getTextLocales()
+ + ", typeface=" + mPaint.getTypeface()
+ + ", variationSettings=" + mPaint.getFontVariationSettings()
+ + ", elegantTextHeight=" + mPaint.isElegantTextHeight()
+ + ", textDir=" + mTextDir
+ + ", breakStrategy=" + mBreakStrategy
+ + ", hyphenationFrequency=" + mHyphenationFrequency
+ + "}";
+ }
};
// The original text.
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 62222b5..533d725 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -213,7 +213,9 @@
byte[] verityRootHash = null;
if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
- verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
+ byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
+ verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
+ verityDigest, apk.length(), signatureInfo);
}
return new VerifiedSigner(
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 9436b29..4431bcef1 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -165,7 +165,7 @@
private static VerifiedSigner verify(
RandomAccessFile apk,
SignatureInfo signatureInfo,
- boolean doVerifyIntegrity) throws SecurityException {
+ boolean doVerifyIntegrity) throws SecurityException, IOException {
int signerCount = 0;
Map<Integer, byte[]> contentDigests = new ArrayMap<>();
VerifiedSigner result = null;
@@ -214,7 +214,9 @@
}
if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
- result.verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
+ byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
+ result.verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
+ verityDigest, apk.length(), signatureInfo);
}
return result;
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 40db758..1c67434 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -285,11 +285,46 @@
return result;
}
+ /**
+ * Return the verity digest only if the length of digest content looks correct.
+ * When verity digest is generated, the last incomplete 4k chunk is padded with 0s before
+ * hashing. This means two almost identical APKs with different number of 0 at the end will have
+ * the same verity digest. To avoid this problem, the length of the source content (excluding
+ * Signing Block) is appended to the verity digest, and the digest is returned only if the
+ * length is consistent to the current APK.
+ */
+ static byte[] parseVerityDigestAndVerifySourceLength(
+ byte[] data, long fileSize, SignatureInfo signatureInfo) throws SecurityException {
+ // FORMAT:
+ // OFFSET DATA TYPE DESCRIPTION
+ // * @+0 bytes uint8[32] Merkle tree root hash of SHA-256
+ // * @+32 bytes int64 Length of source data
+ int kRootHashSize = 32;
+ int kSourceLengthSize = 8;
+
+ if (data.length != kRootHashSize + kSourceLengthSize) {
+ throw new SecurityException("Verity digest size is wrong: " + data.length);
+ }
+ ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
+ buffer.position(kRootHashSize);
+ long expectedSourceLength = buffer.getLong();
+
+ long signingBlockSize = signatureInfo.centralDirOffset
+ - signatureInfo.apkSigningBlockOffset;
+ if (expectedSourceLength != fileSize - signingBlockSize) {
+ throw new SecurityException("APK content size did not verify");
+ }
+
+ return Arrays.copyOfRange(data, 0, kRootHashSize);
+ }
+
private static void verifyIntegrityForVerityBasedAlgorithm(
- byte[] expectedRootHash,
+ byte[] expectedDigest,
RandomAccessFile apk,
SignatureInfo signatureInfo) throws SecurityException {
try {
+ byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,
+ apk.length(), signatureInfo);
ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerity(apk,
signatureInfo, new ByteBufferFactory() {
@Override
@@ -373,9 +408,9 @@
static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
- static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0411;
- static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0413;
- static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0415;
+ static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0421;
+ static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0423;
+ static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0425;
static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 75940e8..77a74e2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -416,4 +416,10 @@
* Returns true if window trace is enabled.
*/
boolean isWindowTraceEnabled();
+
+ /**
+ * Requests that the WindowManager sends WindowManagerPolicy#ACTION_USER_ACTIVITY_NOTIFICATION
+ * on the next user activity.
+ */
+ void requestUserActivityNotification();
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index d7fd329..d8a5609 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -41,8 +41,8 @@
in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets,
out InputChannel outInputChannel);
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
- in int viewVisibility, in int layerStackId, out Rect outContentInsets,
- out Rect outStableInsets, out Rect outOutsets,
+ in int viewVisibility, in int layerStackId, out Rect outFrame,
+ out Rect outContentInsets, out Rect outStableInsets, out Rect outOutsets,
out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel);
int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets);
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 137e820..7a10364 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -51,6 +51,7 @@
private View mHeaderText;
private View mSecondaryHeaderText;
private OnClickListener mExpandClickListener;
+ private OnClickListener mAppOpsListener;
private HeaderTouchListener mTouchListener = new HeaderTouchListener();
private ImageView mExpandButton;
private CachingIconView mIcon;
@@ -267,15 +268,26 @@
}
private void updateTouchListener() {
- if (mExpandClickListener != null) {
- mTouchListener.bindTouchRects();
+ if (mExpandClickListener == null && mAppOpsListener == null) {
+ setOnTouchListener(null);
+ return;
}
+ setOnTouchListener(mTouchListener);
+ mTouchListener.bindTouchRects();
+ }
+
+ /**
+ * Sets onclick listener for app ops icons.
+ */
+ public void setAppOpsOnClickListener(OnClickListener l) {
+ mAppOpsListener = l;
+ mAppOps.setOnClickListener(mAppOpsListener);
+ updateTouchListener();
}
@Override
public void setOnClickListener(@Nullable OnClickListener l) {
mExpandClickListener = l;
- setOnTouchListener(mExpandClickListener != null ? mTouchListener : null);
mExpandButton.setOnClickListener(mExpandClickListener);
updateTouchListener();
}
@@ -308,7 +320,7 @@
* Shows or hides 'app op in use' icons based on app usage.
*/
public void showAppOpsIcons(ArraySet<Integer> appOps) {
- if (mOverlayIcon == null || mCameraIcon == null || mMicIcon == null) {
+ if (mOverlayIcon == null || mCameraIcon == null || mMicIcon == null || appOps == null) {
return;
}
@@ -366,6 +378,7 @@
private final ArrayList<Rect> mTouchRects = new ArrayList<>();
private Rect mExpandButtonRect;
+ private Rect mAppOpsRect;
private int mTouchSlop;
private boolean mTrackGesture;
private float mDownX;
@@ -378,6 +391,7 @@
mTouchRects.clear();
addRectAroundView(mIcon);
mExpandButtonRect = addRectAroundView(mExpandButton);
+ mAppOpsRect = addRectAroundView(mAppOps);
addWidthRect();
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@@ -399,16 +413,18 @@
private Rect getRectAroundView(View view) {
float size = 48 * getResources().getDisplayMetrics().density;
+ float width = Math.max(size, view.getWidth());
+ float height = Math.max(size, view.getHeight());
final Rect r = new Rect();
if (view.getVisibility() == GONE) {
view = getFirstChildNotGone();
- r.left = (int) (view.getLeft() - size / 2.0f);
+ r.left = (int) (view.getLeft() - width / 2.0f);
} else {
- r.left = (int) ((view.getLeft() + view.getRight()) / 2.0f - size / 2.0f);
+ r.left = (int) ((view.getLeft() + view.getRight()) / 2.0f - width / 2.0f);
}
- r.top = (int) ((view.getTop() + view.getBottom()) / 2.0f - size / 2.0f);
- r.bottom = (int) (r.top + size);
- r.right = (int) (r.left + size);
+ r.top = (int) ((view.getTop() + view.getBottom()) / 2.0f - height / 2.0f);
+ r.bottom = (int) (r.top + height);
+ r.right = (int) (r.left + width);
return r;
}
@@ -436,6 +452,11 @@
break;
case MotionEvent.ACTION_UP:
if (mTrackGesture) {
+ if (mAppOps.isVisibleToUser() && (mAppOpsRect.contains((int) x, (int) y)
+ || mAppOpsRect.contains((int) mDownX, (int) mDownY))) {
+ mAppOps.performClick();
+ return true;
+ }
mExpandButton.performClick();
}
break;
diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java
index d597e59..a864e55 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -52,6 +52,9 @@
private final long mDuration;
private final long mStatusBarTransitionDelay;
+ /** @see #getCallingPid */
+ private int mCallingPid;
+
/**
* @param runner The interface that gets notified when we actually need to start the animation.
* @param duration The duration of the animation.
@@ -83,6 +86,20 @@
return mStatusBarTransitionDelay;
}
+ /**
+ * To be called by system_server to keep track which pid is running this animation.
+ */
+ public void setCallingPid(int pid) {
+ mCallingPid = pid;
+ }
+
+ /**
+ * @return The pid of the process running the animation.
+ */
+ public int getCallingPid() {
+ return mCallingPid;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index 381f692..8def435 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -70,6 +70,16 @@
mTransitionAnimationMap = in.readSparseArray(null /* loader */);
}
+ /**
+ * To be called by system_server to keep track which pid is running the remote animations inside
+ * this definition.
+ */
+ public void setCallingPid(int pid) {
+ for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) {
+ mTransitionAnimationMap.valueAt(i).setCallingPid(pid);
+ }
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index facf575..75cdd49 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -109,9 +109,14 @@
*/
public final WindowConfiguration windowConfiguration;
+ /**
+ * Whether the task is not presented in Recents UI.
+ */
+ public boolean isNotInRecents;
+
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
- Rect sourceContainerBounds, WindowConfiguration windowConfig) {
+ Rect sourceContainerBounds, WindowConfiguration windowConfig, boolean isNotInRecents) {
this.mode = mode;
this.taskId = taskId;
this.leash = leash;
@@ -122,6 +127,7 @@
this.position = new Point(position);
this.sourceContainerBounds = new Rect(sourceContainerBounds);
this.windowConfiguration = windowConfig;
+ this.isNotInRecents = isNotInRecents;
}
public RemoteAnimationTarget(Parcel in) {
@@ -135,6 +141,7 @@
position = in.readParcelable(null);
sourceContainerBounds = in.readParcelable(null);
windowConfiguration = in.readParcelable(null);
+ isNotInRecents = in.readBoolean();
}
@Override
@@ -154,6 +161,7 @@
dest.writeParcelable(position, 0 /* flags */);
dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
dest.writeParcelable(windowConfiguration, 0 /* flags */);
+ dest.writeBoolean(isNotInRecents);
}
public static final Creator<RemoteAnimationTarget> CREATOR
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 8830c90..d3b1e5c 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -396,7 +396,44 @@
synchronized (mLock) {
checkNotReleasedLocked();
if (mHwuiContext == null) {
- mHwuiContext = new HwuiContext();
+ mHwuiContext = new HwuiContext(false);
+ }
+ return mHwuiContext.lockCanvas(
+ nativeGetWidth(mNativeObject),
+ nativeGetHeight(mNativeObject));
+ }
+ }
+
+ /**
+ * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut.
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()},
+ * this will return a hardware-accelerated canvas that supports wide color gamut.
+ * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
+ * unsupported drawing operations</a> for a list of what is and isn't
+ * supported in a hardware-accelerated canvas. It is also required to
+ * fully cover the surface every time {@link #lockHardwareCanvas()} is
+ * called as the buffer is not preserved between frames. Partial updates
+ * are not supported.
+ *
+ * @return A canvas for drawing into the surface.
+ *
+ * @throws IllegalStateException If the canvas cannot be locked.
+ *
+ * @hide
+ */
+ public Canvas lockHardwareWideColorGamutCanvas() {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) {
+ mHwuiContext.destroy();
+ mHwuiContext = null;
+ }
+ if (mHwuiContext == null) {
+ mHwuiContext = new HwuiContext(true);
}
return mHwuiContext.lockCanvas(
nativeGetWidth(mNativeObject),
@@ -829,11 +866,14 @@
private final RenderNode mRenderNode;
private long mHwuiRenderer;
private DisplayListCanvas mCanvas;
+ private final boolean mIsWideColorGamut;
- HwuiContext() {
+ HwuiContext(boolean isWideColorGamut) {
mRenderNode = RenderNode.create("HwuiCanvas", null);
mRenderNode.setClipToBounds(false);
- mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
+ mIsWideColorGamut = isWideColorGamut;
+ mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject,
+ isWideColorGamut);
}
Canvas lockCanvas(int width, int height) {
@@ -864,9 +904,13 @@
mHwuiRenderer = 0;
}
}
+
+ boolean isWideColorGamut() {
+ return mIsWideColorGamut;
+ }
}
- private static native long nHwuiCreate(long rootNode, long surface);
+ private static native long nHwuiCreate(long rootNode, long surface, boolean isWideColorGamut);
private static native void nHwuiSetSurface(long renderer, long surface);
private static native void nHwuiDraw(long renderer);
private static native void nHwuiDestroy(long renderer);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4a9da4a..7213923 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,7 +16,6 @@
package android.view;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
@@ -877,31 +876,6 @@
return callbacks;
}
- /**
- * This method still exists only for compatibility reasons because some applications have relied
- * on this method via reflection. See Issue 36345857 for details.
- *
- * @deprecated No platform code is using this method anymore.
- * @hide
- */
- @Deprecated
- public void setWindowType(int type) {
- if (getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
- throw new UnsupportedOperationException(
- "SurfaceView#setWindowType() has never been a public API.");
- }
-
- if (type == TYPE_APPLICATION_PANEL) {
- Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
- + "just to make the SurfaceView to be placed on top of its window, you must "
- + "call setZOrderOnTop(true) instead.", new Throwable());
- setZOrderOnTop(true);
- return;
- }
- Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
- + "type=" + type, new Throwable());
- }
-
private void runOnUiThread(Runnable runnable) {
Handler handler = getHandler();
if (handler != null && handler.getLooper() != Looper.myLooper()) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e996ea1..8d076f7 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -1068,11 +1068,15 @@
mInitialized = true;
mAppContext = context.getApplicationContext();
- nSetDebuggingEnabled(
- (mAppContext.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
- || Build.IS_DEBUGGABLE);
initSched(renderProxy);
- initGraphicsStats();
+
+ if (mAppContext != null) {
+ final boolean appDebuggable =
+ (mAppContext.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)
+ != 0;
+ nSetDebuggingEnabled(appDebuggable || Build.IS_DEBUGGABLE);
+ initGraphicsStats();
+ }
}
private void initSched(long renderProxy) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 853375e..bf0e2eb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7289,16 +7289,18 @@
}
/**
- * If this view is a visually distinct portion of a window, for example the content view of
- * a fragment that is replaced, it is considered a pane for accessibility purposes. In order
- * for accessibility services to understand the views role, and to announce its title as
- * appropriate, such views should have pane titles.
+ * Visually distinct portion of a window with window-like semantics are considered panes for
+ * accessibility purposes. One example is the content view of a fragment that is replaced.
+ * In order for accessibility services to understand a pane's window-like behavior, panes
+ * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s
+ * when they appear, disappear, or change title.
*
- * @param accessibilityPaneTitle The pane's title.
+ * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this
+ * View is not a pane.
*
* {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)}
*/
- public void setAccessibilityPaneTitle(CharSequence accessibilityPaneTitle) {
+ public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) {
if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) {
mAccessibilityPaneTitle = accessibilityPaneTitle;
notifyViewAccessibilityStateChangedIfNeeded(
@@ -7313,7 +7315,7 @@
*
* {@see #setAccessibilityPaneTitle}.
*/
- public CharSequence getAccessibilityPaneTitle() {
+ @Nullable public CharSequence getAccessibilityPaneTitle() {
return mAccessibilityPaneTitle;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 95e4abb..d908e79 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -753,7 +753,7 @@
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(),
+ getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
@@ -1711,8 +1711,8 @@
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
- desiredWindowWidth = dipToPx(config.screenWidthDp);
- desiredWindowHeight = dipToPx(config.screenHeightDp);
+ desiredWindowWidth = mWinFrame.width();
+ desiredWindowHeight = mWinFrame.height();
}
// We used to use the following condition to choose 32 bits drawing caches:
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index a6f36bb..23dc9da 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -51,6 +51,12 @@
int NAV_BAR_BOTTOM = 1 << 2;
/**
+ * Broadcast sent when a user activity is detected.
+ */
+ String ACTION_USER_ACTIVITY_NOTIFICATION =
+ "android.intent.action.USER_ACTIVITY_NOTIFICATION";
+
+ /**
* Sticky broadcast of the current HDMI plugged state.
*/
String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED";
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 5b1dd5c..fdd3f73 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3333,7 +3333,7 @@
final int actionCount = mActions.size();
int nonStandardActionCount = 0;
- int defaultStandardActions = 0;
+ long defaultStandardActions = 0;
for (int i = 0; i < actionCount; i++) {
AccessibilityAction action = mActions.get(i);
if (isDefaultStandardAction(action)) {
@@ -3342,7 +3342,7 @@
nonStandardActionCount++;
}
}
- parcel.writeInt(defaultStandardActions);
+ parcel.writeLong(defaultStandardActions);
parcel.writeInt(nonStandardActionCount);
for (int i = 0; i < actionCount; i++) {
@@ -3353,7 +3353,7 @@
}
}
} else {
- parcel.writeInt(0);
+ parcel.writeLong(0);
parcel.writeInt(0);
}
}
@@ -3540,7 +3540,7 @@
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
- final int standardActions = parcel.readInt();
+ final long standardActions = parcel.readLong();
addStandardActions(standardActions);
final int nonStandardActionCount = parcel.readInt();
for (int i = 0; i < nonStandardActionCount; i++) {
@@ -3621,7 +3621,7 @@
}
private static boolean isDefaultStandardAction(AccessibilityAction action) {
- return action.mSerializationFlag != -1 && TextUtils.isEmpty(action.getLabel());
+ return (action.mSerializationFlag != -1L) && TextUtils.isEmpty(action.getLabel());
}
private static AccessibilityAction getActionSingleton(int actionId) {
@@ -3636,7 +3636,7 @@
return null;
}
- private static AccessibilityAction getActionSingletonBySerializationFlag(int flag) {
+ private static AccessibilityAction getActionSingletonBySerializationFlag(long flag) {
final int actions = AccessibilityAction.sStandardActions.size();
for (int i = 0; i < actions; i++) {
AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
@@ -3648,10 +3648,10 @@
return null;
}
- private void addStandardActions(int serializationIdMask) {
- int remainingIds = serializationIdMask;
+ private void addStandardActions(long serializationIdMask) {
+ long remainingIds = serializationIdMask;
while (remainingIds > 0) {
- final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
+ final long id = 1L << Long.numberOfTrailingZeros(remainingIds);
remainingIds &= ~id;
AccessibilityAction action = getActionSingletonBySerializationFlag(id);
addAction(action);
@@ -4276,7 +4276,7 @@
private final CharSequence mLabel;
/** @hide */
- public int mSerializationFlag = -1;
+ public long mSerializationFlag = -1L;
/**
* Creates a new AccessibilityAction. For adding a standard action without a specific label,
@@ -4310,7 +4310,7 @@
private AccessibilityAction(int standardActionId) {
this(standardActionId, null);
- mSerializationFlag = (int) bitAt(sStandardActions.size());
+ mSerializationFlag = bitAt(sStandardActions.size());
sStandardActions.add(this);
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index c69543f..f0f30a0 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -261,8 +261,7 @@
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
- // TODO(b/68948291): remove this meta-data before release.
- mIsVrOnly = isVrOnly || service.serviceInfo.metaData.getBoolean("isVrOnly", false);
+ mIsVrOnly = isVrOnly;
}
InputMethodInfo(Parcel source) {
diff --git a/core/java/android/view/textclassifier/logging/DefaultLogger.java b/core/java/android/view/textclassifier/DefaultLogger.java
similarity index 99%
rename from core/java/android/view/textclassifier/logging/DefaultLogger.java
rename to core/java/android/view/textclassifier/DefaultLogger.java
index f510879..b2f4e39 100644
--- a/core/java/android/view/textclassifier/logging/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/DefaultLogger.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
similarity index 97%
rename from core/java/android/view/textclassifier/logging/GenerateLinksLogger.java
rename to core/java/android/view/textclassifier/GenerateLinksLogger.java
index fb6f205..73cf43b 100644
--- a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java
+++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.Nullable;
import android.metrics.LogMaker;
import android.util.ArrayMap;
import android.util.Log;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
diff --git a/core/java/android/view/textclassifier/logging/Logger.java b/core/java/android/view/textclassifier/Logger.java
similarity index 98%
rename from core/java/android/view/textclassifier/logging/Logger.java
rename to core/java/android/view/textclassifier/Logger.java
index 4448b2b..a4f5bf1 100644
--- a/core/java/android/view/textclassifier/logging/Logger.java
+++ b/core/java/android/view/textclassifier/Logger.java
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.content.Context;
import android.util.Log;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextSelection;
import com.android.internal.util.Preconditions;
diff --git a/core/java/android/view/textclassifier/logging/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
similarity index 99%
rename from core/java/android/view/textclassifier/logging/SelectionEvent.java
rename to core/java/android/view/textclassifier/SelectionEvent.java
index a8de308..90fd921 100644
--- a/core/java/android/view/textclassifier/logging/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.IntDef;
import android.annotation.Nullable;
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index ec40fdd..ebd2ff9 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -28,7 +28,6 @@
import android.os.Parcelable;
import android.util.ArraySet;
import android.util.Slog;
-import android.view.textclassifier.logging.Logger;
import com.android.internal.util.Preconditions;
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 41f1c69..0a05269 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -34,9 +34,6 @@
import android.provider.Browser;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
-import android.view.textclassifier.logging.DefaultLogger;
-import android.view.textclassifier.logging.GenerateLinksLogger;
-import android.view.textclassifier.logging.Logger;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8149dc9..f39b73e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3126,6 +3126,11 @@
mProvider.getViewDelegate().onActivityResult(requestCode, resultCode, data);
}
+ @Override
+ public boolean onCheckIsTextEditor() {
+ return mProvider.getViewDelegate().onCheckIsTextEditor();
+ }
+
/** @hide */
@Override
protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 805cac0..00e782b 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -427,6 +427,11 @@
public Handler getHandler(Handler originalHandler);
public View findFocus(View originalFocusedView);
+
+ @SuppressWarnings("unused")
+ default boolean onCheckIsTextEditor() {
+ return false;
+ }
}
interface ScrollDelegate {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 1d1fcc9..61a5873 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -863,7 +863,7 @@
}
final int range = getMax() - getMin();
- progress += scale * range;
+ progress += scale * range + getMin();
setHotspot(x, y);
setProgressInternal(Math.round(progress), true, false);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index fe49c02..92285c7 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -37,6 +38,7 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
@@ -99,6 +101,7 @@
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.LinearInterpolator;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
@@ -200,11 +203,11 @@
private final boolean mHapticTextHandleEnabled;
- private final Magnifier mMagnifier;
+ private final MagnifierMotionAnimator mMagnifierAnimator;
private final Runnable mUpdateMagnifierRunnable = new Runnable() {
@Override
public void run() {
- mMagnifier.update();
+ mMagnifierAnimator.update();
}
};
// Update the magnifier contents whenever anything in the view hierarchy is updated.
@@ -215,7 +218,7 @@
new ViewTreeObserver.OnDrawListener() {
@Override
public void onDraw() {
- if (mMagnifier != null) {
+ if (mMagnifierAnimator != null) {
// Posting the method will ensure that updating the magnifier contents will
// happen right after the rendering of the current frame.
mTextView.post(mUpdateMagnifierRunnable);
@@ -371,7 +374,9 @@
mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableHapticTextHandle);
- mMagnifier = FLAG_USE_MAGNIFIER ? new Magnifier(mTextView) : null;
+ if (FLAG_USE_MAGNIFIER) {
+ mMagnifierAnimator = new MagnifierMotionAnimator(new Magnifier(mTextView));
+ }
}
ParcelableParcel saveInstanceState() {
@@ -4309,6 +4314,88 @@
}
}
+ private static class MagnifierMotionAnimator {
+ private static final long DURATION = 100 /* miliseconds */;
+
+ // The magnifier being animated.
+ private final Magnifier mMagnifier;
+ // A value animator used to animate the magnifier.
+ private final ValueAnimator mAnimator;
+
+ // Whether the magnifier is currently visible.
+ private boolean mMagnifierIsShowing;
+ // The coordinates of the magnifier when the currently running animation started.
+ private float mAnimationStartX;
+ private float mAnimationStartY;
+ // The coordinates of the magnifier in the latest animation frame.
+ private float mAnimationCurrentX;
+ private float mAnimationCurrentY;
+ // The latest coordinates the motion animator was asked to #show() the magnifier at.
+ private float mLastX;
+ private float mLastY;
+
+ private MagnifierMotionAnimator(final Magnifier magnifier) {
+ mMagnifier = magnifier;
+ // Prepare the animator used to run the motion animation.
+ mAnimator = ValueAnimator.ofFloat(0, 1);
+ mAnimator.setDuration(DURATION);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ mAnimator.addUpdateListener((animation) -> {
+ // Interpolate to find the current position of the magnifier.
+ mAnimationCurrentX = mAnimationStartX
+ + (mLastX - mAnimationStartX) * animation.getAnimatedFraction();
+ mAnimationCurrentY = mAnimationStartY
+ + (mLastY - mAnimationStartY) * animation.getAnimatedFraction();
+ mMagnifier.show(mAnimationCurrentX, mAnimationCurrentY);
+ });
+ }
+
+ /**
+ * Shows the magnifier at a new position.
+ * If the y coordinate is different from the previous y coordinate
+ * (probably corresponding to a line jump in the text), a short
+ * animation is added to the jump.
+ */
+ private void show(final float x, final float y) {
+ final boolean startNewAnimation = mMagnifierIsShowing && y != mLastY;
+
+ if (startNewAnimation) {
+ if (mAnimator.isRunning()) {
+ mAnimator.cancel();
+ mAnimationStartX = mAnimationCurrentX;
+ mAnimationStartY = mAnimationCurrentY;
+ } else {
+ mAnimationStartX = mLastX;
+ mAnimationStartY = mLastY;
+ }
+ mAnimator.start();
+ } else {
+ if (!mAnimator.isRunning()) {
+ mMagnifier.show(x, y);
+ }
+ }
+ mLastX = x;
+ mLastY = y;
+ mMagnifierIsShowing = true;
+ }
+
+ /**
+ * Updates the content of the magnifier.
+ */
+ private void update() {
+ mMagnifier.update();
+ }
+
+ /**
+ * Dismisses the magnifier, or does nothing if it is already dismissed.
+ */
+ private void dismiss() {
+ mMagnifier.dismiss();
+ mAnimator.cancel();
+ mMagnifierIsShowing = false;
+ }
+ }
+
@VisibleForTesting
public abstract class HandleView extends View implements TextViewPositionListener {
protected Drawable mDrawable;
@@ -4648,52 +4735,106 @@
return 0;
}
- protected final void showMagnifier(@NonNull final MotionEvent event) {
- if (mMagnifier == null) {
- return;
- }
+ /**
+ * Computes the position where the magnifier should be shown, relative to
+ * {@code mTextView}, and writes them to {@code showPosInView}. Also decides
+ * whether the magnifier should be shown or dismissed after this touch event.
+ * @return Whether the magnifier should be shown at the computed coordinates or dismissed.
+ */
+ private boolean obtainMagnifierShowCoordinates(@NonNull final MotionEvent event,
+ final PointF showPosInView) {
final int trigger = getMagnifierHandleTrigger();
final int offset;
+ final int otherHandleOffset;
switch (trigger) {
- case MagnifierHandleTrigger.INSERTION: // Fall through.
+ case MagnifierHandleTrigger.INSERTION:
+ offset = mTextView.getSelectionStart();
+ otherHandleOffset = -1;
+ break;
case MagnifierHandleTrigger.SELECTION_START:
offset = mTextView.getSelectionStart();
+ otherHandleOffset = mTextView.getSelectionEnd();
break;
case MagnifierHandleTrigger.SELECTION_END:
offset = mTextView.getSelectionEnd();
+ otherHandleOffset = mTextView.getSelectionStart();
break;
default:
offset = -1;
+ otherHandleOffset = -1;
break;
}
if (offset == -1) {
- dismissMagnifier();
+ return false;
}
final Layout layout = mTextView.getLayout();
final int lineNumber = layout.getLineForOffset(offset);
- // Horizontally move the magnifier smoothly.
+ // Compute whether the selection handles are currently on the same line, and,
+ // in this particular case, whether the selected text is right to left.
+ final boolean sameLineSelection = otherHandleOffset != -1
+ && lineNumber == layout.getLineForOffset(otherHandleOffset);
+ final boolean rtl = sameLineSelection
+ && (offset < otherHandleOffset)
+ != (getHorizontal(mTextView.getLayout(), offset)
+ < getHorizontal(mTextView.getLayout(), otherHandleOffset));
+
+ // Horizontally move the magnifier smoothly, clamp inside the current line / selection.
final int[] textViewLocationOnScreen = new int[2];
mTextView.getLocationOnScreen(textViewLocationOnScreen);
- final float xPosInView = event.getRawX() - textViewLocationOnScreen[0];
+ final float touchXInView = event.getRawX() - textViewLocationOnScreen[0];
+ float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+ float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+ if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) {
+ leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
+ } else {
+ leftBound += mTextView.getLayout().getLineLeft(lineNumber);
+ }
+ if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) {
+ rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
+ } else {
+ rightBound += mTextView.getLayout().getLineRight(lineNumber);
+ }
+ final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth()
+ / mMagnifierAnimator.mMagnifier.getZoom());
+ if (touchXInView < leftBound - contentWidth / 2
+ || touchXInView > rightBound + contentWidth / 2) {
+ // The touch is too far from the current line / selection, so hide the magnifier.
+ return false;
+ }
+ showPosInView.x = Math.max(leftBound, Math.min(rightBound, touchXInView));
+
// Vertically snap to middle of current line.
- final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
+ showPosInView.y = (mTextView.getLayout().getLineTop(lineNumber)
+ mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
+ mTextView.getTotalPaddingTop() - mTextView.getScrollY();
- // Make the cursor visible and stop blinking.
- mRenderCursorRegardlessTiming = true;
- mTextView.invalidateCursorPath();
- suspendBlink();
+ return true;
+ }
- mMagnifier.show(xPosInView, yPosInView);
+ protected final void updateMagnifier(@NonNull final MotionEvent event) {
+ if (mMagnifierAnimator == null) {
+ return;
+ }
+
+ final PointF showPosInView = new PointF();
+ final boolean shouldShow = obtainMagnifierShowCoordinates(event, showPosInView);
+ if (shouldShow) {
+ // Make the cursor visible and stop blinking.
+ mRenderCursorRegardlessTiming = true;
+ mTextView.invalidateCursorPath();
+ suspendBlink();
+ mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
+ } else {
+ dismissMagnifier();
+ }
}
protected final void dismissMagnifier() {
- if (mMagnifier != null) {
- mMagnifier.dismiss();
+ if (mMagnifierAnimator != null) {
+ mMagnifierAnimator.dismiss();
mRenderCursorRegardlessTiming = false;
resumeBlink();
}
@@ -4877,11 +5018,11 @@
case MotionEvent.ACTION_DOWN:
mDownPositionX = ev.getRawX();
mDownPositionY = ev.getRawY();
- showMagnifier(ev);
+ updateMagnifier(ev);
break;
case MotionEvent.ACTION_MOVE:
- showMagnifier(ev);
+ updateMagnifier(ev);
break;
case MotionEvent.ACTION_UP:
@@ -5235,11 +5376,11 @@
// re-engages the handle.
mTouchWordDelta = 0.0f;
mPrevX = UNSET_X_VALUE;
- showMagnifier(event);
+ updateMagnifier(event);
break;
case MotionEvent.ACTION_MOVE:
- showMagnifier(event);
+ updateMagnifier(event);
break;
case MotionEvent.ACTION_UP:
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 85f68d7..e2601dc 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -23,6 +23,7 @@
import android.annotation.UiThread;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Outline;
@@ -34,6 +35,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.DisplayListCanvas;
import android.view.LayoutInflater;
@@ -49,6 +51,7 @@
import android.view.ViewParent;
import android.view.ViewRootImpl;
+import com.android.internal.R;
import com.android.internal.util.Preconditions;
/**
@@ -75,12 +78,16 @@
private final int mWindowWidth;
// The height of the window containing the magnifier.
private final int mWindowHeight;
+ // The zoom applied to the view region copied to the magnifier window.
+ private final float mZoom;
// The width of the bitmaps where the magnifier content is copied.
private final int mBitmapWidth;
// The height of the bitmaps where the magnifier content is copied.
private final int mBitmapHeight;
// The elevation of the window containing the magnifier.
private final float mWindowElevation;
+ // The corner radius of the window containing the magnifier.
+ private final float mWindowCornerRadius;
// The center coordinates of the content that is to be magnified.
private final Point mCenterZoomCoords = new Point();
// Variables holding previous states, used for detecting redundant calls and invalidation.
@@ -102,19 +109,15 @@
public Magnifier(@NonNull View view) {
mView = Preconditions.checkNotNull(view);
final Context context = mView.getContext();
- final View content = LayoutInflater.from(context).inflate(
- com.android.internal.R.layout.magnifier, null);
- content.findViewById(com.android.internal.R.id.magnifier_inner).setClipToOutline(true);
- mWindowWidth = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.magnifier_width);
- mWindowHeight = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.magnifier_height);
- mWindowElevation = context.getResources().getDimension(
- com.android.internal.R.dimen.magnifier_elevation);
- final float zoomScale = context.getResources().getFloat(
- com.android.internal.R.dimen.magnifier_zoom_scale);
- mBitmapWidth = Math.round(mWindowWidth / zoomScale);
- mBitmapHeight = Math.round(mWindowHeight / zoomScale);
+ final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
+ content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
+ mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
+ mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
+ mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
+ mWindowCornerRadius = getDeviceDefaultDialogCornerRadius();
+ mZoom = context.getResources().getFloat(R.dimen.magnifier_zoom_scale);
+ mBitmapWidth = Math.round(mWindowWidth / mZoom);
+ mBitmapHeight = Math.round(mWindowHeight / mZoom);
// The view's surface coordinates will not be updated until the magnifier is first shown.
mViewCoordinatesInSurface = new int[2];
}
@@ -124,6 +127,21 @@
}
/**
+ * Returns the device default theme dialog corner radius attribute.
+ * We retrieve this from the device default theme to avoid
+ * using the values set in the custom application themes.
+ */
+ private float getDeviceDefaultDialogCornerRadius() {
+ final Context deviceDefaultContext =
+ new ContextThemeWrapper(mView.getContext(), R.style.Theme_DeviceDefault);
+ final TypedArray ta = deviceDefaultContext.obtainStyledAttributes(
+ new int[]{android.R.attr.dialogCornerRadius});
+ final float dialogCornerRadius = ta.getDimension(0, 0);
+ ta.recycle();
+ return dialogCornerRadius;
+ }
+
+ /**
* Shows the magnifier on the screen.
*
* @param xPosInView horizontal coordinate of the center point of the magnifier source relative
@@ -176,7 +194,8 @@
if (mWindow == null) {
synchronized (mLock) {
mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
- getValidViewSurface(), mWindowWidth, mWindowHeight, mWindowElevation,
+ getValidViewSurface(),
+ mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius,
Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
mCallback);
}
@@ -187,21 +206,6 @@
}
}
- @Nullable
- private Surface getValidViewSurface() {
- // TODO: deduplicate this against the first part of #performPixelCopy
- final Surface surface;
- if (mView instanceof SurfaceView) {
- surface = ((SurfaceView) mView).getHolder().getSurface();
- } else if (mView.getViewRootImpl() != null) {
- surface = mView.getViewRootImpl().mSurface;
- } else {
- surface = null;
- }
-
- return (surface != null && surface.isValid()) ? surface : null;
- }
-
/**
* Dismisses the magnifier from the screen. Calling this on a dismissed magnifier is a no-op.
*/
@@ -226,6 +230,44 @@
}
}
+ /**
+ * @return The width of the magnifier window, in pixels.
+ */
+ public int getWidth() {
+ return mWindowWidth;
+ }
+
+ /**
+ * @return The height of the magnifier window, in pixels.
+ */
+ public int getHeight() {
+ return mWindowHeight;
+ }
+
+ /**
+ * @return The zoom applied to the magnified view region copied to the magnifier window.
+ * If the zoom is x and the magnifier window size is (width, height), the original size
+ * of the content copied in the magnifier will be (width / x, height / x).
+ */
+ public float getZoom() {
+ return mZoom;
+ }
+
+ @Nullable
+ private Surface getValidViewSurface() {
+ // TODO: deduplicate this against the first part of #performPixelCopy
+ final Surface surface;
+ if (mView instanceof SurfaceView) {
+ surface = ((SurfaceView) mView).getHolder().getSurface();
+ } else if (mView.getViewRootImpl() != null) {
+ surface = mView.getViewRootImpl().mSurface;
+ } else {
+ surface = null;
+ }
+
+ return (surface != null && surface.isValid()) ? surface : null;
+ }
+
private void configureCoordinates(final float xPosInView, final float yPosInView) {
// Compute the coordinates of the center of the content going to be displayed in the
// magnifier. These are relative to the surface the content is copied from.
@@ -246,7 +288,7 @@
// Compute the position of the magnifier window. Again, this has to be relative to the
// surface of the magnified view, as this surface is the parent of the magnifier surface.
final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.magnifier_offset);
+ R.dimen.magnifier_offset);
mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset;
}
@@ -368,7 +410,7 @@
InternalPopupWindow(final Context context, final Display display,
final Surface parentSurface,
- final int width, final int height, final float elevation,
+ final int width, final int height, final float elevation, final float cornerRadius,
final Handler handler, final Object lock, final Callback callback) {
mDisplay = display;
mLock = lock;
@@ -399,7 +441,8 @@
);
mBitmapRenderNode = createRenderNodeForBitmap(
"magnifier content",
- elevation
+ elevation,
+ cornerRadius
);
final DisplayListCanvas canvas = mRenderer.getRootNode().start(width, height);
@@ -417,7 +460,8 @@
mFrameDrawScheduled = false;
}
- private RenderNode createRenderNodeForBitmap(final String name, final float elevation) {
+ private RenderNode createRenderNodeForBitmap(final String name,
+ final float elevation, final float cornerRadius) {
final RenderNode bitmapRenderNode = RenderNode.create(name, null);
// Define the position of the bitmap in the parent render node. The surface regions
@@ -427,7 +471,7 @@
bitmapRenderNode.setElevation(elevation);
final Outline outline = new Outline();
- outline.setRoundRect(0, 0, mContentWidth, mContentHeight, 3);
+ outline.setRoundRect(0, 0, mContentWidth, mContentHeight, cornerRadius);
outline.setAlpha(1.0f);
bitmapRenderNode.setOutline(outline);
bitmapRenderNode.setClipToOutline(true);
@@ -602,7 +646,7 @@
return null;
}
synchronized (mWindow.mLock) {
- return mWindow.mBitmap;
+ return Bitmap.createScaledBitmap(mWindow.mBitmap, mWindowWidth, mWindowHeight, true);
}
}
@@ -633,8 +677,8 @@
final Resources resources = Resources.getSystem();
final float density = resources.getDisplayMetrics().density;
final PointF size = new PointF();
- size.x = resources.getDimension(com.android.internal.R.dimen.magnifier_width) / density;
- size.y = resources.getDimension(com.android.internal.R.dimen.magnifier_height) / density;
+ size.x = resources.getDimension(R.dimen.magnifier_width) / density;
+ size.y = resources.getDimension(R.dimen.magnifier_height) / density;
return size;
}
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index adc4432..3ec8ab9 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -176,6 +176,7 @@
* @hide TODO: remove once the implementation is revised
*/
public void setController(MediaController controller) {
+ mProvider.setController_impl(controller);
}
/**
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 519a7dd..225497b 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1990,28 +1990,15 @@
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- // special case for the back key, we do not even try to send it
- // to the drop down list but instead, consume it immediately
- if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
- KeyEvent.DispatcherState state = getKeyDispatcherState();
- if (state != null) {
- state.startTracking(event, this);
- }
- return true;
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- KeyEvent.DispatcherState state = getKeyDispatcherState();
- if (state != null) {
- state.handleUpEvent(event);
- }
- if (event.isTracking() && !event.isCanceled()) {
- mSearchView.clearFocus();
- setImeVisibility(false);
- return true;
- }
- }
+ final boolean consume = super.onKeyPreIme(keyCode, event);
+ if (consume && keyCode == KeyEvent.KEYCODE_BACK
+ && event.getAction() == KeyEvent.ACTION_UP) {
+ // If AutoCompleteTextView closed its pop-up, it will return true, in which case
+ // we should also close the IME. Otherwise, the popup is already closed and we can
+ // leave the BACK event alone.
+ setImeVisibility(false);
}
- return super.onKeyPreIme(keyCode, event);
+ return consume;
}
/**
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 8e93078..629f531 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,13 +33,13 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.ActionMode;
+import android.view.textclassifier.Logger;
+import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextSelection;
-import android.view.textclassifier.logging.Logger;
-import android.view.textclassifier.logging.SelectionEvent;
import android.widget.Editor.SelectionModifierCursorController;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6e40ea8..6fe64a0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4141,6 +4141,7 @@
*/
public void setTextMetricsParams(@NonNull PrecomputedText.Params params) {
mTextPaint.set(params.getTextPaint());
+ mUserSetTextScaleX = true;
mTextDir = params.getTextDirection();
mBreakStrategy = params.getBreakStrategy();
mHyphenationFrequency = params.getHyphenationFrequency();
@@ -5528,9 +5529,16 @@
* {@link android.text.Editable.Factory} to create final or intermediate
* {@link Editable Editables}.
*
+ * If the passed text is a {@link PrecomputedText} but the parameters used to create the
+ * PrecomputedText mismatches with this TextView, IllegalArgumentException is thrown. To ensure
+ * the parameters match, you can call {@link TextView#setTextMetricsParams} before calling this.
+ *
* @param text text to be displayed
*
* @attr ref android.R.styleable#TextView_text
+ * @throws IllegalArgumentException if the passed text is a {@link PrecomputedText} but the
+ * parameters used to create the PrecomputedText mismatches
+ * with this TextView.
*/
@android.view.RemotableViewMethod
public final void setText(CharSequence text) {
@@ -5644,7 +5652,21 @@
if (imm != null) imm.restartInput(this);
} else if (type == BufferType.SPANNABLE || mMovement != null) {
text = mSpannableFactory.newSpannable(text);
- } else if (!(text instanceof PrecomputedText || text instanceof CharWrapper)) {
+ } else if (text instanceof PrecomputedText) {
+ PrecomputedText precomputed = (PrecomputedText) text;
+ if (mTextDir == null) {
+ mTextDir = getTextDirectionHeuristic();
+ }
+ if (!precomputed.getParams().isSameTextMetricsInternal(
+ getPaint(), mTextDir, mBreakStrategy, mHyphenationFrequency)) {
+ throw new IllegalArgumentException(
+ "PrecomputedText's Parameters don't match the parameters of this TextView."
+ + "Consider using setTextMetricsParams(precomputedText.getParams()) "
+ + "to override the settings of this TextView: "
+ + "PrecomputedText: " + precomputed.getParams()
+ + "TextView: " + getTextMetricsParams());
+ }
+ } else if (!(text instanceof CharWrapper)) {
text = TextUtils.stringOrSpannedString(text);
}
@@ -8062,7 +8084,9 @@
return false;
}
- private void nullLayouts() {
+ /** @hide */
+ @VisibleForTesting
+ public void nullLayouts() {
if (mLayout instanceof BoringLayout && mSavedLayout == null) {
mSavedLayout = (BoringLayout) mLayout;
}
@@ -8156,7 +8180,8 @@
* not the full view width with padding.
* {@hide}
*/
- protected void makeNewLayout(int wantWidth, int hintWidth,
+ @VisibleForTesting
+ public void makeNewLayout(int wantWidth, int hintWidth,
BoringLayout.Metrics boring,
BoringLayout.Metrics hintBoring,
int ellipsisWidth, boolean bringIntoView) {
@@ -8446,7 +8471,9 @@
return mIncludePad;
}
- private static final BoringLayout.Metrics UNKNOWN_BORING = new BoringLayout.Metrics();
+ /** @hide */
+ @VisibleForTesting
+ public static final BoringLayout.Metrics UNKNOWN_BORING = new BoringLayout.Metrics();
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 09ff337..6f08dc2 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -26,10 +26,8 @@
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.MediaPlayer2;
-import android.media.MediaPlayerBase;
import android.media.SessionToken2;
import android.media.session.MediaController;
-import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.media.update.ApiLoader;
import android.media.update.VideoView2Provider;
@@ -279,40 +277,6 @@
mProvider.setAudioAttributes_impl(attributes);
}
- // TODO: unhide this method when MediaPlayerInterface became unhidden.
- /**
- * Sets a remote player for handling playback of the selected route from MediaControlView2.
- * If this is not called, MediaCotrolView2 will not show the route button.
- *
- * @param routeCategories the list of media control categories in
- * {@link android.support.v7.media.MediaControlIntent}
- * @param player the player to handle playback of the selected route.
- * If null, a default route player will be used.
- * @throws IllegalStateException if MediaControlView2 is not set.
- * @hide
- */
- public void setRouteAttributes(@NonNull List<String> routeCategories,
- @Nullable MediaPlayerBase player) {
- mProvider.setRouteAttributes_impl(routeCategories, player);
- }
-
- /**
- * Sets a remote player for handling playback of the selected route from MediaControlView2.
- * If this is not called, MediaCotrolView2 will not show the route button.
- *
- * @param routeCategories the list of media control categories in
- * {@link android.support.v7.media.MediaControlIntent}
- * @param sessionPlayer the player to handle playback of the selected route.
- * If null, a default route player will be used.
- * @throws IllegalStateException if MediaControlView2 is not set.
- * @hide
- */
- // TODO: Use MediaPlayerBase once MediaSession2 APIs are ready.
- public void setRouteAttributes(@NonNull List<String> routeCategories,
- @Nullable MediaSession.Callback sessionPlayer) {
- mProvider.setRouteAttributes_impl(routeCategories, sessionPlayer);
- }
-
/**
* Sets video path.
*
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
deleted file mode 100644
index 04d7f9b..0000000
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.inputmethod;
-
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
-
-import java.util.Objects;
-
-public class InputMethodSubtypeHandle {
- private final String mInputMethodId;
- private final int mSubtypeId;
-
- public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) {
- mInputMethodId = info.getId();
- if (subtype != null) {
- mSubtypeId = subtype.hashCode();
- } else {
- mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID;
- }
- }
-
- public InputMethodSubtypeHandle(String inputMethodId, int subtypeId) {
- mInputMethodId = inputMethodId;
- mSubtypeId = subtypeId;
- }
-
- public String getInputMethodId() {
- return mInputMethodId;
- }
-
- public int getSubtypeId() {
- return mSubtypeId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null || !(o instanceof InputMethodSubtypeHandle)) {
- return false;
- }
- InputMethodSubtypeHandle other = (InputMethodSubtypeHandle) o;
- return TextUtils.equals(mInputMethodId, other.getInputMethodId())
- && mSubtypeId == other.getSubtypeId();
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(mInputMethodId) * 31 + mSubtypeId;
- }
-
- @Override
- public String toString() {
- return "InputMethodSubtypeHandle{mInputMethodId=" + mInputMethodId
- + ", mSubtypeId=" + mSubtypeId + "}";
- }
-}
diff --git a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
index ce45f3c..e790e08 100644
--- a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
@@ -123,6 +123,17 @@
}
}
+ public void readAbsolute(Callback cb) {
+ synchronized (mProcReader) {
+ readDelta(null);
+ int total = mLastUidCpuActiveTimeMs.size();
+ for (int i = 0; i < total; i ++){
+ int uid = mLastUidCpuActiveTimeMs.keyAt(i);
+ cb.onUidCpuActiveTime(uid, mLastUidCpuActiveTimeMs.get(uid).longValue());
+ }
+ }
+ }
+
public void removeUid(int uid) {
mLastUidCpuActiveTimeMs.delete(uid);
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
index c21b766..bf5b520 100644
--- a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
@@ -65,6 +65,7 @@
private double[] mCurTime; // Reuse to avoid GC.
private long[] mDeltaTime; // Reuse to avoid GC.
+ private long[] mCurTimeRounded; // Reuse to avoid GC.
public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
/**
@@ -137,6 +138,21 @@
}
}
+ public void readAbsolute(Callback cb) {
+ synchronized (mProcReader) {
+ readDelta(null);
+ int total = mLastUidPolicyTimeMs.size();
+ for (int i = 0; i < total; i ++){
+ int uid = mLastUidPolicyTimeMs.keyAt(i);
+ double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
+ for (int j = 0; j < mNumClusters; j++) {
+ mCurTimeRounded[j] = (long) lastTimes[j];
+ }
+ cb.onUidCpuPolicyTime(uid, mCurTimeRounded);
+ }
+ }
+ }
+
private void processUid(IntBuffer buf, @Nullable Callback cb) {
int uid = buf.get();
double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
@@ -189,6 +205,7 @@
mNumCoresOnCluster = numCoresOnCluster;
mCurTime = new double[numClusters];
mDeltaTime = new long[numClusters];
+ mCurTimeRounded = new long[numClusters];
return true;
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index a0787a0..f65074f 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -226,6 +226,17 @@
}
}
+ public void readAbsolute(Callback cb) {
+ synchronized (mProcReader) {
+ readDelta(null);
+ int total = mLastUidCpuFreqTimeMs.size();
+ for (int i = 0; i < total; i ++){
+ int uid = mLastUidCpuFreqTimeMs.keyAt(i);
+ cb.onUidCpuFreqTime(uid, mLastUidCpuFreqTimeMs.get(uid));
+ }
+ }
+ }
+
public void removeUid(int uid) {
mLastUidCpuFreqTimeMs.delete(uid);
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 4263b83..97b7211 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -135,6 +135,30 @@
}
/**
+ * Reads the proc file, calling into the callback with raw absolute value of time for each UID.
+ * @param callback The callback to invoke for each line of the proc file.
+ */
+ public void readAbsolute(Callback callback) {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
+ TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
+ String line;
+ while ((line = reader.readLine()) != null) {
+ splitter.setString(line);
+ final String uidStr = splitter.next();
+ final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10);
+ final long userTimeUs = Long.parseLong(splitter.next(), 10);
+ final long systemTimeUs = Long.parseLong(splitter.next(), 10);
+ callback.onUidCpuTime(uid, userTimeUs, systemTimeUs);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ }
+
+ /**
* Removes the UID from the kernel module and from internal accounting data. Only
* {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
* visible system wide.
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 344c772..246a50f 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -38,11 +38,6 @@
*/
public class PowerProfile {
- /**
- * No power consumption, or accounted for elsewhere.
- */
- public static final String POWER_NONE = "none";
-
/*
* POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode.
* POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 72cd248..6c3a58c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -147,8 +147,17 @@
}
mStartRtc.delete(action);
Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
- long duration = endRtc - startRtc;
+ logAction(action, (int)(endRtc - startRtc));
+ }
+
+ /**
+ * Logs an action that has started and ended. This needs to be called from the main thread.
+ *
+ * @param action The action to end. One of the ACTION_* values.
+ * @param duration The duration of the action in ms.
+ */
+ public static void logAction(int action, int duration) {
Log.i(TAG, "action=" + action + " latency=" + duration);
- EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, (int) duration);
+ EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
}
}
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
index 518cf41..b962d4f 100644
--- a/core/java/com/android/internal/util/NotificationMessagingUtil.java
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -78,6 +78,10 @@
return false;
}
+ return isMessaging(sbn);
+ }
+
+ public boolean isMessaging(StatusBarNotification sbn) {
Class<? extends Notification.Style> style = sbn.getNotification().getNotificationStyle();
if (Notification.MessagingStyle.class.equals(style)) {
return true;
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 6dff8b4..bf3e8d5 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -47,6 +47,7 @@
*/
final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener,
PopupWindow.OnDismissListener {
+ private static final int ITEM_LAYOUT = com.android.internal.R.layout.cascading_menu_item_layout;
@Retention(RetentionPolicy.SOURCE)
@IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
@@ -348,7 +349,7 @@
*/
private void showMenu(@NonNull MenuBuilder menu) {
final LayoutInflater inflater = LayoutInflater.from(mContext);
- final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly);
+ final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly, ITEM_LAYOUT);
// Apply "force show icon" setting. There are 3 cases:
// (1) This is the top level menu and icon spacing is forced. Add spacing.
diff --git a/core/java/com/android/internal/view/menu/MenuAdapter.java b/core/java/com/android/internal/view/menu/MenuAdapter.java
index 2834d39..5bc981b 100644
--- a/core/java/com/android/internal/view/menu/MenuAdapter.java
+++ b/core/java/com/android/internal/view/menu/MenuAdapter.java
@@ -23,8 +23,6 @@
import java.util.ArrayList;
public class MenuAdapter extends BaseAdapter {
- static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
-
MenuBuilder mAdapterMenu;
private int mExpandedIndex = -1;
@@ -32,11 +30,14 @@
private boolean mForceShowIcon;
private final boolean mOverflowOnly;
private final LayoutInflater mInflater;
+ private final int mItemLayoutRes;
- public MenuAdapter(MenuBuilder menu, LayoutInflater inflater, boolean overflowOnly) {
+ public MenuAdapter(MenuBuilder menu, LayoutInflater inflater, boolean overflowOnly,
+ int itemLayoutRes) {
mOverflowOnly = overflowOnly;
mInflater = inflater;
mAdapterMenu = menu;
+ mItemLayoutRes = itemLayoutRes;
findExpandedIndex();
}
@@ -78,7 +79,7 @@
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
- convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
+ convertView = mInflater.inflate(mItemLayoutRes, parent, false);
}
final int currGroupId = getItem(position).getGroupId();
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 445379b..d618f67 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -43,6 +43,7 @@
*/
final class StandardMenuPopup extends MenuPopup implements OnDismissListener, OnItemClickListener,
MenuPresenter, OnKeyListener {
+ private static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
private final Context mContext;
@@ -116,7 +117,7 @@
mMenu = menu;
mOverflowOnly = overflowOnly;
final LayoutInflater inflater = LayoutInflater.from(context);
- mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly);
+ mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly, ITEM_LAYOUT);
mPopupStyleAttr = popupStyleAttr;
mPopupStyleRes = popupStyleRes;
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index e3b1c01..35aae15 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1784,7 +1784,8 @@
private static Context applyDefaultTheme(Context originalContext) {
TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
boolean isLightTheme = a.getBoolean(0, true);
- int themeId = isLightTheme ? R.style.Theme_Material_Light : R.style.Theme_Material;
+ int themeId
+ = isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault;
a.recycle();
return new ContextThemeWrapper(originalContext, themeId);
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 5a06f7f..25e1589 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -54,13 +54,6 @@
void userPresent(int userId);
int getStrongAuthForUser(int userId);
- long addEscrowToken(in byte[] token, int userId);
- boolean removeEscrowToken(long handle, int userId);
- boolean isEscrowTokenActive(long handle, int userId);
- boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
- in byte[] token, int requestedQuality, int userId);
- void unlockUserWithToken(long tokenHandle, in byte[] token, int userId);
-
// Keystore RecoveryController methods.
// {@code ServiceSpecificException} may be thrown to signal an error, which caller can
// convert to {@code RecoveryManagerException}.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e871003..bf075bf 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -42,8 +42,10 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
+import android.util.SparseLongArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.google.android.collect.Lists;
import libcore.util.HexEncoding;
@@ -120,8 +122,6 @@
@Deprecated
public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
- public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
- public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
@Deprecated
@@ -164,6 +164,7 @@
private ILockSettings mLockSettingsService;
private UserManager mUserManager;
private final Handler mHandler;
+ private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
/**
* Use {@link TrustManager#isTrustUsuallyManaged(int)}.
@@ -1237,8 +1238,7 @@
// enforces the deadline. Since we cannot store settings for the FRP user, don't.
return deadline;
}
- setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
- setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
+ mLockoutDeadlines.put(userId, deadline);
return deadline;
}
@@ -1248,22 +1248,13 @@
* enter a pattern.
*/
public long getLockoutAttemptDeadline(int userId) {
- long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
- final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
+ final long deadline = mLockoutDeadlines.get(userId, 0L);
final long now = SystemClock.elapsedRealtime();
if (deadline < now && deadline != 0) {
// timeout expired
- setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
- setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
+ mLockoutDeadlines.put(userId, 0);
return 0L;
}
-
- if (deadline > (now + timeoutMs)) {
- // device was rebooted, set new deadline
- deadline = now + timeoutMs;
- setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
- }
-
return deadline;
}
@@ -1483,6 +1474,13 @@
}
}
+ private LockSettingsInternal getLockSettingsInternal() {
+ LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
+ if (service == null) {
+ throw new SecurityException("Only available to system server itself");
+ }
+ return service;
+ }
/**
* Create an escrow token for the current user, which can later be used to unlock FBE
* or change user password.
@@ -1491,44 +1489,41 @@
* confirm credential operation in order to activate the token for future use. If the user
* has no secure lockscreen, then the token is activated immediately.
*
+ * <p>This method is only available to code running in the system server process itself.
+ *
* @return a unique 64-bit token handle which is needed to refer to this token later.
*/
public long addEscrowToken(byte[] token, int userId) {
- try {
- return getLockSettings().addEscrowToken(token, userId);
- } catch (RemoteException re) {
- return 0L;
- }
+ return getLockSettingsInternal().addEscrowToken(token, userId);
}
/**
* Remove an escrow token.
+ *
+ * <p>This method is only available to code running in the system server process itself.
+ *
* @return true if the given handle refers to a valid token previously returned from
* {@link #addEscrowToken}, whether it's active or not. return false otherwise.
*/
public boolean removeEscrowToken(long handle, int userId) {
- try {
- return getLockSettings().removeEscrowToken(handle, userId);
- } catch (RemoteException re) {
- return false;
- }
+ return getLockSettingsInternal().removeEscrowToken(handle, userId);
}
/**
* Check if the given escrow token is active or not. Only active token can be used to call
* {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+ *
+ * <p>This method is only available to code running in the system server process itself.
*/
public boolean isEscrowTokenActive(long handle, int userId) {
- try {
- return getLockSettings().isEscrowTokenActive(handle, userId);
- } catch (RemoteException re) {
- return false;
- }
+ return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
}
/**
* Change a user's lock credential with a pre-configured escrow token.
*
+ * <p>This method is only available to code running in the system server process itself.
+ *
* @param credential The new credential to be set
* @param type Credential type: password / pattern / none.
* @param requestedQuality the requested password quality by DevicePolicyManager.
@@ -1540,55 +1535,55 @@
*/
public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
long tokenHandle, byte[] token, int userId) {
- try {
- if (type != CREDENTIAL_TYPE_NONE) {
- if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
- throw new IllegalArgumentException("password must not be null and at least "
- + "of length " + MIN_LOCK_PASSWORD_SIZE);
- }
- final int quality = computePasswordQuality(type, credential, requestedQuality);
- if (!getLockSettings().setLockCredentialWithToken(credential, type, tokenHandle,
- token, quality, userId)) {
- return false;
- }
- setLong(PASSWORD_TYPE_KEY, quality, userId);
-
- updateEncryptionPasswordIfNeeded(credential, quality, userId);
- updatePasswordHistory(credential, userId);
- } else {
- if (!TextUtils.isEmpty(credential)) {
- throw new IllegalArgumentException("password must be emtpy for NONE type");
- }
- if (!getLockSettings().setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
- tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- userId)) {
- return false;
- }
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- userId);
-
- if (userId == UserHandle.USER_SYSTEM) {
- // Set the encryption password to default.
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- setCredentialRequiredToDecrypt(false);
- }
+ LockSettingsInternal localService = getLockSettingsInternal();
+ if (type != CREDENTIAL_TYPE_NONE) {
+ if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
+ throw new IllegalArgumentException("password must not be null and at least "
+ + "of length " + MIN_LOCK_PASSWORD_SIZE);
}
- onAfterChangingPassword(userId);
- return true;
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to save lock password ", re);
- re.rethrowFromSystemServer();
+ final int quality = computePasswordQuality(type, credential, requestedQuality);
+ if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
+ token, quality, userId)) {
+ return false;
+ }
+ setLong(PASSWORD_TYPE_KEY, quality, userId);
+
+ updateEncryptionPasswordIfNeeded(credential, quality, userId);
+ updatePasswordHistory(credential, userId);
+ } else {
+ if (!TextUtils.isEmpty(credential)) {
+ throw new IllegalArgumentException("password must be emtpy for NONE type");
+ }
+ if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
+ tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+ userId)) {
+ return false;
+ }
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+ userId);
+
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Set the encryption password to default.
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ setCredentialRequiredToDecrypt(false);
+ }
}
- return false;
+ onAfterChangingPassword(userId);
+ return true;
}
- public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
- try {
- getLockSettings().unlockUserWithToken(tokenHandle, token, userId);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to unlock user with token", re);
- re.rethrowFromSystemServer();
- }
+ /**
+ * Unlock the specified user by an pre-activated escrow token. This should have the same effect
+ * on device encryption as the user entering his lockscreen credentials for the first time after
+ * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
+ *
+ * <p>This method is only available to code running in the system server process itself.
+ *
+ * @return {@code true} if the supplied token is valid and unlock succeeds,
+ * {@code false} otherwise.
+ */
+ public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+ return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
new file mode 100644
index 0000000..9de9ef7
--- /dev/null
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.widget;
+
+
+/**
+ * LockSettingsService local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class LockSettingsInternal {
+
+ /**
+ * Create an escrow token for the current user, which can later be used to unlock FBE
+ * or change user password.
+ *
+ * After adding, if the user currently has lockscreen password, he will need to perform a
+ * confirm credential operation in order to activate the token for future use. If the user
+ * has no secure lockscreen, then the token is activated immediately.
+ *
+ * @return a unique 64-bit token handle which is needed to refer to this token later.
+ */
+ public abstract long addEscrowToken(byte[] token, int userId);
+
+ /**
+ * Remove an escrow token.
+ * @return true if the given handle refers to a valid token previously returned from
+ * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
+ */
+ public abstract boolean removeEscrowToken(long handle, int userId);
+
+ /**
+ * Check if the given escrow token is active or not. Only active token can be used to call
+ * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+ */
+ public abstract boolean isEscrowTokenActive(long handle, int userId);
+
+ public abstract boolean setLockCredentialWithToken(String credential, int type,
+ long tokenHandle, byte[] token, int requestedQuality, int userId);
+
+ public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
+}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8b1de2f..9d4b5aa 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -284,8 +284,9 @@
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
- // Allow ODM to customize system configs around libs, features and apps
- int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
+ // Allow ODM to customize system configs as much as Vendor, because /odm is another
+ // vendor partition other than /vendor.
+ int odmPermissionFlag = vendorPermissionFlag;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
@@ -631,7 +632,9 @@
// granting permissions to priv apps in the system partition and vice
// versa.
boolean vendor = permFile.toPath().startsWith(
- Environment.getVendorDirectory().toPath());
+ Environment.getVendorDirectory().toPath())
+ || permFile.toPath().startsWith(
+ Environment.getOdmDirectory().toPath());
boolean product = permFile.toPath().startsWith(
Environment.getProductDirectory().toPath());
if (vendor) {
diff --git a/core/java/com/android/server/net/BaseNetdEventCallback.java b/core/java/com/android/server/net/BaseNetdEventCallback.java
new file mode 100644
index 0000000..3d3a3d0
--- /dev/null
+++ b/core/java/com/android/server/net/BaseNetdEventCallback.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.net;
+
+import android.net.INetdEventCallback;
+
+/**
+ * Base {@link INetdEventCallback} that provides no-op
+ * implementations which can be overridden.
+ *
+ * @hide
+ */
+public class BaseNetdEventCallback extends INetdEventCallback.Stub {
+ @Override
+ public void onDnsEvent(String hostname, String[] ipAddresses,
+ int ipAddressesCount, long timestamp, int uid) {
+ // default no-op
+ }
+
+ @Override
+ public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
+ // default no-op
+ }
+}
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ed032c7..c7ad2a4 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -51,6 +51,18 @@
std::vector<minikin::FontVariation> axes;
};
+static inline NativeFamilyBuilder* toNativeBuilder(jlong ptr) {
+ return reinterpret_cast<NativeFamilyBuilder*>(ptr);
+}
+
+static inline FontFamilyWrapper* toFamily(jlong ptr) {
+ return reinterpret_cast<FontFamilyWrapper*>(ptr);
+}
+
+template<typename Ptr> static inline jlong toJLong(Ptr ptr) {
+ return reinterpret_cast<jlong>(ptr);
+}
+
static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring langs, jint variant) {
NativeFamilyBuilder* builder;
if (langs != nullptr) {
@@ -59,15 +71,14 @@
} else {
builder = new NativeFamilyBuilder(minikin::registerLocaleList(""), variant);
}
- return reinterpret_cast<jlong>(builder);
+ return toJLong(builder);
}
static jlong FontFamily_create(jlong builderPtr) {
if (builderPtr == 0) {
return 0;
}
- std::unique_ptr<NativeFamilyBuilder> builder(
- reinterpret_cast<NativeFamilyBuilder*>(builderPtr));
+ NativeFamilyBuilder* builder = toNativeBuilder(builderPtr);
if (builder->fonts.empty()) {
return 0;
}
@@ -76,17 +87,23 @@
if (family->getCoverage().length() == 0) {
return 0;
}
- return reinterpret_cast<jlong>(new FontFamilyWrapper(std::move(family)));
+ return toJLong(new FontFamilyWrapper(std::move(family)));
}
-static void FontFamily_abort(jlong builderPtr) {
- NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
- delete builder;
+static void releaseBuilder(jlong builderPtr) {
+ delete toNativeBuilder(builderPtr);
}
-static void FontFamily_unref(jlong familyPtr) {
- FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
- delete family;
+static jlong FontFamily_getBuilderReleaseFunc() {
+ return toJLong(&releaseBuilder);
+}
+
+static void releaseFamily(jlong familyPtr) {
+ delete toFamily(familyPtr);
+}
+
+static jlong FontFamily_getFamilyReleaseFunc() {
+ return toJLong(&releaseFamily);
}
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
@@ -175,7 +192,7 @@
static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr,
jobject font, jint ttcIndex, jint weight, jint isItalic) {
NPE_CHECK_RETURN_ZERO(env, font);
- NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+ NativeFamilyBuilder* builder = toNativeBuilder(builderPtr);
const void* fontPtr = env->GetDirectBufferAddress(font);
if (fontPtr == NULL) {
ALOGE("addFont failed to create font, buffer invalid");
@@ -204,8 +221,7 @@
NPE_CHECK_RETURN_ZERO(env, jassetMgr);
NPE_CHECK_RETURN_ZERO(env, jpath);
- NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-
+ NativeFamilyBuilder* builder = toNativeBuilder(builderPtr);
Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr);
if (NULL == mgr) {
builder->axes.clear();
@@ -249,19 +265,19 @@
}
static void FontFamily_addAxisValue(jlong builderPtr, jint tag, jfloat value) {
- NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
+ NativeFamilyBuilder* builder = toNativeBuilder(builderPtr);
builder->axes.push_back({static_cast<minikin::AxisTag>(tag), value});
}
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gFontFamilyMethods[] = {
- { "nInitBuilder", "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder },
- { "nCreateFamily", "(J)J", (void*)FontFamily_create },
- { "nAbort", "(J)V", (void*)FontFamily_abort },
- { "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
- { "nAddFont", "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont },
- { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;III)Z",
+ { "nInitBuilder", "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder },
+ { "nCreateFamily", "(J)J", (void*)FontFamily_create },
+ { "nGetBuilderReleaseFunc", "()J", (void*)FontFamily_getBuilderReleaseFunc },
+ { "nGetFamilyReleaseFunc", "()J", (void*)FontFamily_getFamilyReleaseFunc },
+ { "nAddFont", "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont },
+ { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;III)Z",
(void*)FontFamily_addFontWeightStyle },
{ "nAddFontFromAssetManager", "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZIII)Z",
(void*)FontFamily_addFontFromAssetManager },
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index d67c0b0..34ec365 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -28,8 +28,16 @@
using namespace android;
+static inline Typeface* toTypeface(jlong ptr) {
+ return reinterpret_cast<Typeface*>(ptr);
+}
+
+template<typename Ptr> static inline jlong toJLong(Ptr ptr) {
+ return reinterpret_cast<jlong>(ptr);
+}
+
static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
- Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
+ Typeface* family = toTypeface(familyHandle);
Typeface* face = Typeface::createRelative(family, (Typeface::Style)style);
// TODO: the following logic shouldn't be necessary, the above should always succeed.
// Try to find the closest matching font, using the standard heuristic
@@ -39,13 +47,12 @@
for (int i = 0; NULL == face && i < 4; i++) {
face = Typeface::createRelative(family, (Typeface::Style)i);
}
- return reinterpret_cast<jlong>(face);
+ return toJLong(face);
}
static jlong Typeface_createFromTypefaceWithExactStyle(JNIEnv* env, jobject, jlong nativeInstance,
jint weight, jboolean italic) {
- Typeface* baseTypeface = reinterpret_cast<Typeface*>(nativeInstance);
- return reinterpret_cast<jlong>(Typeface::createAbsolute(baseTypeface, weight, italic));
+ return toJLong(Typeface::createAbsolute(toTypeface(nativeInstance), weight, italic));
}
static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
@@ -60,30 +67,30 @@
AxisHelper axis(env, axisObject);
variations.push_back(minikin::FontVariation(axis.getTag(), axis.getStyleValue()));
}
- Typeface* baseTypeface = reinterpret_cast<Typeface*>(familyHandle);
- Typeface* result = Typeface::createFromTypefaceWithVariation(baseTypeface, variations);
- return reinterpret_cast<jlong>(result);
+ return toJLong(Typeface::createFromTypefaceWithVariation(toTypeface(familyHandle), variations));
}
static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
- Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
- Typeface* face = Typeface::createWithDifferentBaseWeight(family, weight);
- return reinterpret_cast<jlong>(face);
+ return toJLong(Typeface::createWithDifferentBaseWeight(toTypeface(familyHandle), weight));
}
-static void Typeface_unref(JNIEnv* env, jobject obj, jlong faceHandle) {
- Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- delete face;
+static void releaseFunc(jlong ptr) {
+ delete toTypeface(ptr);
}
-static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) {
- Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- return face->fAPIStyle;
+// CriticalNative
+static jlong Typeface_getReleaseFunc() {
+ return toJLong(&releaseFunc);
}
-static jint Typeface_getWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
- Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- return face->fStyle.weight();
+// CriticalNative
+static jint Typeface_getStyle(jlong faceHandle) {
+ return toTypeface(faceHandle)->fAPIStyle;
+}
+
+// CriticalNative
+static jint Typeface_getWeight(jlong faceHandle) {
+ return toTypeface(faceHandle)->fStyle.weight();
}
static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
@@ -95,17 +102,16 @@
FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]);
familyVec.emplace_back(family->family);
}
- return reinterpret_cast<jlong>(
- Typeface::createFromFamilies(std::move(familyVec), weight, italic));
+ return toJLong(Typeface::createFromFamilies(std::move(familyVec), weight, italic));
}
-static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
- Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- Typeface::setDefault(face);
+// CriticalNative
+static void Typeface_setDefault(jlong faceHandle) {
+ Typeface::setDefault(toTypeface(faceHandle));
}
static jobject Typeface_getSupportedAxes(JNIEnv *env, jobject, jlong faceHandle) {
- Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
+ Typeface* face = toTypeface(faceHandle);
const std::unordered_set<minikin::AxisTag>& tagSet = face->fFontCollection->getSupportedTags();
const size_t length = tagSet.size();
if (length == 0) {
@@ -131,7 +137,7 @@
{ "nativeCreateFromTypefaceWithVariation", "(JLjava/util/List;)J",
(void*)Typeface_createFromTypefaceWithVariation },
{ "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias },
- { "nativeUnref", "(J)V", (void*)Typeface_unref },
+ { "nativeGetReleaseFunc", "()J", (void*)Typeface_getReleaseFunc },
{ "nativeGetStyle", "(J)I", (void*)Typeface_getStyle },
{ "nativeGetWeight", "(J)I", (void*)Typeface_getWeight },
{ "nativeCreateFromArray", "([JII)J",
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 12da273..da4cdb6 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -78,11 +78,11 @@
case ENCODING_AAC_ELD:
return AUDIO_FORMAT_AAC_ELD;
case ENCODING_AAC_XHE:
- return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
+ return AUDIO_FORMAT_AAC_XHE;
case ENCODING_AC4:
return AUDIO_FORMAT_AC4;
- // case ENCODING_E_AC3_JOC: // FIXME Not defined on the native side yet
- // return AUDIO_FORMAT_E_AC3_JOC;
+ case ENCODING_E_AC3_JOC:
+ return AUDIO_FORMAT_E_AC3_JOC;
case ENCODING_DEFAULT:
return AUDIO_FORMAT_DEFAULT;
default:
@@ -133,8 +133,8 @@
// return ENCODING_AAC_XHE;
case AUDIO_FORMAT_AC4:
return ENCODING_AC4;
- // case AUDIO_FORMAT_E_AC3_JOC: // FIXME Not defined on the native side yet
- // return ENCODING_E_AC3_JOC;
+ case AUDIO_FORMAT_E_AC3_JOC:
+ return ENCODING_E_AC3_JOC;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f5c09fd..f70cf07 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -546,12 +546,16 @@
}
};
-static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr) {
+static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr,
+ jboolean isWideColorGamut) {
RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
ContextFactory factory;
RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
proxy->loadSystemProperties();
+ if (isWideColorGamut) {
+ proxy->setWideGamut(true);
+ }
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
proxy->initialize(surface);
// Shadows can't be used via this interface, so just set the light source
@@ -620,7 +624,7 @@
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
// HWUI context
- {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
+ {"nHwuiCreate", "(JJZ)J", (void*) hwui::create },
{"nHwuiSetSurface", "(JJ)V", (void*) hwui::setSurface },
{"nHwuiDraw", "(J)V", (void*) hwui::draw },
{"nHwuiDestroy", "(J)V", (void*) hwui::destroy },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d6fe568..d05be2c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -488,6 +488,8 @@
if (errno != 0) {
ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
}
+ // Update base::logging default tag.
+ android::base::SetDefaultTag(buf);
}
// The list of open zygote file descriptors.
@@ -685,10 +687,10 @@
// Make it easier to debug audit logs by setting the main thread's name to the
// nice name rather than "app_process".
- if (se_info_c_str == NULL && is_system_server) {
+ if (se_name_c_str == NULL && is_system_server) {
se_name_c_str = "system_server";
}
- if (se_info_c_str != NULL) {
+ if (se_name_c_str != NULL) {
SetThreadName(se_name_c_str);
}
diff --git a/core/proto/README.md b/core/proto/README.md
new file mode 100644
index 0000000..d2b89a5
--- /dev/null
+++ b/core/proto/README.md
@@ -0,0 +1,41 @@
+Conventions for the protos in this directory:
+
+1. As in the rest of Android, use 4 spaces to indent instead of 2.
+
+1. For protos based on Java files, use the same package as the Java file. For
+ example, `com.android.server.thing` instead of `com.android.server.thing.proto`.
+
+1. If the proto describes the top level output of dumpsys, it should contain
+ `Dump`. This makes it easy to understand that the proto is the dumpsys output
+ of a certain service, not the data structure of that service, e.g.
+ `WindowManagerServiceDumpProto` vs `WindowManagerServiceDumpProto`.
+
+ * Inner messages whose containing messages have the `Proto` suffix do not
+ need to have a `Proto` suffix. E.g:
+
+```
+message FooProto {
+ message Bar {
+ ...
+ }
+}
+```
+
+ vs
+
+```
+message FooProto {
+ message BarProto {
+ ...
+ }
+}
+```
+
+1. If the proto represents the structure of an object, it should have `Proto` as
+ its suffix. Please also include the full package path of the original object
+ as a comment to the proto message.
+
+1. Include units in the field names. For example, `screen_time_ms` vs
+ `screen_time`, or `file_size_bytes` or `file_size_mebibytes` vs `file_size`.
+
+1. Leave field numbers 50,000 - 100,000 reserved for OEMs.
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index 06ae2d3..9e459e6 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -21,10 +21,23 @@
option java_multiple_files = true;
// Bluetooth connection states.
-// Primarily used by android/bluetooth/BluetoothAdapter.java
enum ConnectionStateEnum {
CONNECTION_STATE_DISCONNECTED = 0;
CONNECTION_STATE_CONNECTING = 1;
CONNECTION_STATE_CONNECTED = 2;
CONNECTION_STATE_DISCONNECTING = 3;
+}
+
+// Bluetooth Adapter Enable and Disable Reasons
+enum EnableDisableReasonEnum {
+ ENABLE_DISABLE_REASON_UNSPECIFIED = 0;
+ ENABLE_DISABLE_REASON_APPLICATION_REQUEST = 1;
+ ENABLE_DISABLE_REASON_AIRPLANE_MODE = 2;
+ ENABLE_DISABLE_REASON_DISALLOWED = 3;
+ ENABLE_DISABLE_REASON_RESTARTED = 4;
+ ENABLE_DISABLE_REASON_START_ERROR = 5;
+ ENABLE_DISABLE_REASON_SYSTEM_BOOT = 6;
+ ENABLE_DISABLE_REASON_CRASH = 7;
+ ENABLE_DISABLE_REASON_USER_SWITCH = 8;
+ ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
}
\ No newline at end of file
diff --git a/core/proto/android/os/backtrace.proto b/core/proto/android/os/backtrace.proto
new file mode 100644
index 0000000..ba81386
--- /dev/null
+++ b/core/proto/android/os/backtrace.proto
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+message BackTraceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ message Stack {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 pid = 1;
+ optional string dump = 2;
+ // Time it took to dump the stacktrace.
+ optional int64 dump_duration_ns = 3;
+ }
+ repeated Stack traces = 1;
+}
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 9915174..f468143 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -641,9 +641,7 @@
message Job {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string name = 1 [
- (android.privacy).dest = DEST_EXPLICIT
- ];
+ optional string name = 1;
// Job times aren't apportioned.
optional TimerProto total = 2;
optional TimerProto background = 3;
@@ -654,9 +652,7 @@
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Job name.
- optional string name = 1 [
- (android.privacy).dest = DEST_EXPLICIT
- ];
+ optional string name = 1;
message ReasonCount {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -801,9 +797,7 @@
message Sync {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string name = 1 [
- (android.privacy).dest = DEST_EXPLICIT
- ];
+ optional string name = 1;
// Sync times aren't apportioned.
optional TimerProto total = 2;
optional TimerProto background = 3;
@@ -842,9 +836,7 @@
message Wakelock {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string name = 1 [
- (android.privacy).dest = DEST_EXPLICIT
- ];
+ optional string name = 1;
// Full wakelocks keep the screen on. Based on
// PowerManager.SCREEN_BRIGHT_WAKE_LOCK (deprecated in API 13) and
@@ -876,9 +868,7 @@
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Wakeup alarm name.
- optional string name = 1 [
- (android.privacy).dest = DEST_EXPLICIT
- ];
+ optional string name = 1;
// Only includes counts when screen-off (& on battery).
optional int32 count = 2;
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 7326829..4657dc4 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -17,6 +17,7 @@
syntax = "proto2";
option java_multiple_files = true;
+import "frameworks/base/core/proto/android/os/backtrace.proto";
import "frameworks/base/core/proto/android/os/batterytype.proto";
import "frameworks/base/core/proto/android/os/cpufreq.proto";
import "frameworks/base/core/proto/android/os/cpuinfo.proto";
@@ -115,6 +116,22 @@
(section).args = "LOG_ID_KERNEL"
];
+ // Stack dumps
+ optional android.os.BackTraceProto native_traces = 1200 [
+ (section).type = SECTION_TOMBSTONE,
+ (section).args = "native"
+ ];
+
+ optional android.os.BackTraceProto hal_traces = 1201 [
+ (section).type = SECTION_TOMBSTONE,
+ (section).args = "hal"
+ ];
+
+ optional android.os.BackTraceProto java_traces = 1202 [
+ (section).type = SECTION_TOMBSTONE,
+ (section).args = "java"
+ ];
+
// Linux services
optional ProcrankProto procrank = 2000 [
(section).type = SECTION_NONE, // disable procrank until figure out permission
@@ -263,4 +280,7 @@
(section).type = SECTION_DUMPSYS,
(section).args = "usb --proto"
];
+
+ // Reserved for OEMs.
+ extensions 50000 to 100000;
}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 69abed3..9193129 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -614,7 +614,6 @@
CONSTRAINT_DEADLINE = 5;
CONSTRAINT_IDLE = 6;
CONSTRAINT_CONNECTIVITY = 7;
- CONSTRAINT_APP_NOT_IDLE = 8;
CONSTRAINT_CONTENT_TRIGGER = 9;
CONSTRAINT_DEVICE_NOT_DOZING = 10;
}
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 5cb5319..64aa98b 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -315,4 +315,6 @@
optional bool is_double_tap_wake_enabled = 37;
// True if we are currently in VR Mode.
optional bool is_vr_mode_enabled = 38;
+ // True if Sidekick is controlling the display and we shouldn't change its power mode.
+ optional bool draw_wake_lock_override_from_sidekick = 39;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3324fc3..f521e4b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -56,6 +56,7 @@
<protected-broadcast android:name="android.intent.action.SPLIT_CONFIGURATION_CHANGED" />
<protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
<protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.BATTERY_LEVEL_CHANGED" />
<protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
<protected-broadcast android:name="android.intent.action.BATTERY_OKAY" />
<protected-broadcast android:name="android.intent.action.ACTION_POWER_CONNECTED" />
@@ -87,6 +88,7 @@
<protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" />
<protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
<protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -3093,8 +3095,8 @@
<!-- Allows an application to collect ambient light stats.
<p>Not for use by third party applications.</p>
- TODO: Make a system API
- @hide -->
+ @hide
+ @SystemApi -->
<permission android:name="android.permission.ACCESS_AMBIENT_LIGHT_STATS"
android:protectionLevel="signature|privileged|development" />
diff --git a/core/res/res/color/control_nodisable_material.xml b/core/res/res/color/config_progress_background_tint.xml
similarity index 92%
rename from core/res/res/color/control_nodisable_material.xml
rename to core/res/res/color/config_progress_background_tint.xml
index 4a73e93..b086e20 100644
--- a/core/res/res/color/control_nodisable_material.xml
+++ b/core/res/res/color/config_progress_background_tint.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2018 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.
diff --git a/core/res/res/drawable/floating_popup_background_dark.xml b/core/res/res/drawable/floating_popup_background_dark.xml
index ded1137..c4b4448 100644
--- a/core/res/res/drawable/floating_popup_background_dark.xml
+++ b/core/res/res/drawable/floating_popup_background_dark.xml
@@ -16,8 +16,8 @@
*/
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
+ android:shape="rectangle">
<solid android:color="@color/background_floating_material_dark" />
- <corners android:radius="2dp" />
+ <corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
diff --git a/core/res/res/drawable/floating_popup_background_light.xml b/core/res/res/drawable/floating_popup_background_light.xml
index 9c7a886..767140d 100644
--- a/core/res/res/drawable/floating_popup_background_light.xml
+++ b/core/res/res/drawable/floating_popup_background_light.xml
@@ -18,6 +18,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/background_floating_material_light" />
- <corners android:radius="2dp" />
+ <corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml
index 2f94d0c..d59abf4 100644
--- a/core/res/res/drawable/progress_horizontal_material.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -18,7 +18,7 @@
<item android:id="@id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle"
- android:tint="?attr/colorControlNormal">
+ android:tint="?attr/colorProgressBackgroundNormal">
<corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/progress_bar_height_material" />
<solid android:color="@color/white_disabled_material" />
diff --git a/core/res/res/drawable/seekbar_track_material.xml b/core/res/res/drawable/seekbar_track_material.xml
index 62ef136..2076fee 100644
--- a/core/res/res/drawable/seekbar_track_material.xml
+++ b/core/res/res/drawable/seekbar_track_material.xml
@@ -18,7 +18,7 @@
<item android:id="@id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle"
- android:tint="@color/control_nodisable_material">
+ android:tint="?attr/colorProgressBackgroundNormal">
<corners android:radius="?attr/progressBarCornerRadius" />
<size android:height="@dimen/seekbar_track_background_height_material" />
<solid android:color="@color/white_disabled_material" />
diff --git a/core/res/res/layout/cascading_menu_item_layout.xml b/core/res/res/layout/cascading_menu_item_layout.xml
new file mode 100644
index 0000000..7d18635
--- /dev/null
+++ b/core/res/res/layout/cascading_menu_item_layout.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<!-- Keep in sync with popup_menu_item_layout.xml (which only differs in the title and shortcut
+ position). -->
+<com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minWidth="196dip"
+ android:orientation="vertical" >
+
+ <ImageView
+ android:id="@+id/group_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginTop="4dip"
+ android:layout_marginBottom="4dip"
+ android:background="@drawable/list_divider_material" />
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ android:paddingEnd="16dip"
+ android:duplicateParentState="true" >
+
+ <!-- Icon will be inserted here. -->
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="16dip"
+ android:textAppearance="?attr/textAppearanceLargePopupMenu"
+ android:singleLine="true"
+ android:duplicateParentState="true"
+ android:textAlignment="viewStart" />
+
+ <Space
+ android:layout_width="0dip"
+ android:layout_height="1dip"
+ android:layout_weight="1"/>
+
+ <TextView
+ android:id="@+id/shortcut"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="16dip"
+ android:textAppearance="?attr/textAppearanceSmallPopupMenu"
+ android:singleLine="true"
+ android:duplicateParentState="true"
+ android:textAlignment="viewEnd" />
+
+ <ImageView
+ android:id="@+id/submenuarrow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="8dp"
+ android:scaleType="center"
+ android:visibility="gone" />
+
+ <!-- Checkbox, and/or radio button will be inserted here. -->
+
+ </LinearLayout>
+
+</com.android.internal.view.menu.ListMenuItemView>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index c03cf51..3196d00 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -129,8 +129,9 @@
<LinearLayout
android:id="@+id/app_ops"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_width="wrap_content"
+ android:layout_marginStart="6dp"
android:orientation="horizontal" >
<ImageButton
android:id="@+id/camera"
@@ -139,7 +140,6 @@
android:src="@drawable/ic_camera"
android:tint="@color/notification_secondary_text_color_light"
android:background="?android:selectableItemBackgroundBorderless"
- android:layout_marginStart="6dp"
android:visibility="gone"
/>
<ImageButton
diff --git a/core/res/res/values-as-watch/strings.xml b/core/res/res/values-as-watch/strings.xml
new file mode 100644
index 0000000..1c91d10
--- /dev/null
+++ b/core/res/res/values-as-watch/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for android_upgrading_apk (1090732262010398759) -->
+ <skip />
+ <string name="permgrouplab_sensors" msgid="202675452368612754">"ছেন্সৰসমূহ"</string>
+</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
new file mode 100644
index 0000000..5ab2fa6
--- /dev/null
+++ b/core/res/res/values-as/strings.xml
@@ -0,0 +1,2006 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="byteShort" msgid="8340973892742019101">"বা."</string>
+ <string name="kilobyteShort" msgid="7542884022844556968">"কে. বি."</string>
+ <string name="megabyteShort" msgid="6355851576770428922">"এম. বি."</string>
+ <string name="gigabyteShort" msgid="3259882455212193214">"জি. বি."</string>
+ <string name="terabyteShort" msgid="231613018159186962">"টি. বি."</string>
+ <string name="petabyteShort" msgid="5637816680144990219">"পি. বি."</string>
+ <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled" msgid="4638956954852782576">"<শিৰোনামবিহীন>"</string>
+ <string name="emptyPhoneNumber" msgid="7694063042079676517">"(কোনো ফ\'ন নম্বৰ নাই)"</string>
+ <string name="unknownName" msgid="6867811765370350269">"অজ্ঞাত"</string>
+ <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ভইচমেইল"</string>
+ <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
+ <string name="mmiError" msgid="5154499457739052907">"সংযোগৰ সমস্যা বা MMI ক\'ড মান্য নহয়।"</string>
+ <string name="mmiFdnError" msgid="5224398216385316471">"কেৱল ফিক্সড ডায়েলিং নম্বৰৰ বাবে কার্য সীমাবদ্ধ কৰা হৈছে।"</string>
+ <string name="mmiErrorWhileRoaming" msgid="762488890299284230">"আপুনি ৰ\'মিঙত থকাৰ সময়ত কল ফৰৱাৰ্ডিঙৰ ছেটিংসমূহ সলনি কৰিব নোৱাৰি।"</string>
+ <string name="serviceEnabled" msgid="8147278346414714315">"সেৱা সক্ষম কৰা হ\'ল।"</string>
+ <string name="serviceEnabledFor" msgid="6856228140453471041">"সেৱা সক্ষম কৰা হ\'ল:"</string>
+ <string name="serviceDisabled" msgid="1937553226592516411">"সেৱা অক্ষম কৰা হ\'ল।"</string>
+ <string name="serviceRegistered" msgid="6275019082598102493">"পঞ্জীকৰণ সফল হ\'ল।"</string>
+ <string name="serviceErased" msgid="1288584695297200972">"সফলভাৱে মচা হ\'ল৷"</string>
+ <string name="passwordIncorrect" msgid="7612208839450128715">"ভুল পাছৱৰ্ড৷"</string>
+ <string name="mmiComplete" msgid="8232527495411698359">"MMI সম্পূৰ্ণ হ’ল।"</string>
+ <string name="badPin" msgid="9015277645546710014">"আপুনি লিখা পুৰণি পিনটো শুদ্ধ নহয়।"</string>
+ <string name="badPuk" msgid="5487257647081132201">"আপুনি লিখা PUKটো শুদ্ধ নহয়।"</string>
+ <string name="mismatchPin" msgid="609379054496863419">"আপুনি লিখা পিনবিলাক মিলা নাই।"</string>
+ <string name="invalidPin" msgid="3850018445187475377">"৪টাৰ পৰা ৮টা সংখ্যাযুক্ত এটা পিন লিখক।"</string>
+ <string name="invalidPuk" msgid="8761456210898036513">"৮টা সংখ্যা বা তাতকৈ বেছি সংখ্যাৰ এটা PUK লিখক।"</string>
+ <string name="needPuk" msgid="919668385956251611">"আপোনাৰ ছিমটো PUK ক\'ডেৰে লক কৰা আছে। PUK ক\'ড লিখি ইয়াক আনলক কৰক।"</string>
+ <string name="needPuk2" msgid="4526033371987193070">"ছিম কার্ড আনলক কৰিবলৈ PUK2 দিয়ক৷"</string>
+ <string name="enablePin" msgid="209412020907207950">"অসফল, ছিম/RUIM লক সক্ষম কৰক।"</string>
+ <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+ <item quantity="one">ছিম লক হোৱাৰ পূৰ্বে আপোনাৰ <xliff:g id="NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে।</item>
+ <item quantity="other">ছিম লক হোৱাৰ পূৰ্বে আপোনাৰ <xliff:g id="NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে।</item>
+ </plurals>
+ <string name="imei" msgid="2625429890869005782">"IMEI"</string>
+ <string name="meid" msgid="4841221237681254195">"MEID"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"অন্তৰ্গামী কলাৰ আইডি"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"বহিৰ্গামী কলাৰ আইডি"</string>
+ <string name="ColpMmi" msgid="3065121483740183974">"সংযোজিত লাইন আইডি"</string>
+ <string name="ColrMmi" msgid="4996540314421889589">"সংযোজিত লাইন আইডিৰ সীমাবদ্ধতা"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"কল ফৰৱাৰ্ডিং"</string>
+ <string name="CwMmi" msgid="9129678056795016867">"কল অপেক্ষাৰত"</string>
+ <string name="BaMmi" msgid="455193067926770581">"কল অৱৰোধ কৰা সুবিধা"</string>
+ <string name="PwdMmi" msgid="7043715687905254199">"পাছৱর্ড সলনি কৰা"</string>
+ <string name="PinMmi" msgid="3113117780361190304">"পিন সলনি কৰা"</string>
+ <string name="CnipMmi" msgid="3110534680557857162">"বর্তমান কল কৰা নম্বৰ"</string>
+ <string name="CnirMmi" msgid="3062102121430548731">"বর্তমান কল কৰা নম্বৰ সীমিত কৰা হ\'ল"</string>
+ <string name="ThreeWCMmi" msgid="9051047170321190368">"ত্ৰিপক্ষীয় কলিং"</string>
+ <string name="RuacMmi" msgid="7827887459138308886">"আমনিদায়ক কল প্ৰত্যাখ্যান"</string>
+ <string name="CndMmi" msgid="3116446237081575808">"কল কৰা নম্বৰত ডেলিভাৰী"</string>
+ <string name="DndMmi" msgid="1265478932418334331">"অসুবিধা নিদিব"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"কলাৰ আইডি সীমিত কৰিবলৈ পূর্বনির্ধাৰণ কৰা হৈছে। পৰৱৰ্তী কল: সীমিত কৰা হৈছে"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"কলাৰ আইডি সীমিত কৰিবলৈ পূর্বনির্ধাৰণ কৰা হৈছে। পৰৱৰ্তী কল: সীমিত কৰা হৈছে"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"কলাৰ আইডি সীমিত নকৰিবলৈ পূর্বনির্ধাৰণ কৰা হৈছে। পৰৱৰ্তী কল: সীমিত কৰা হোৱা নাই"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"কলাৰ আইডি সীমিত নকৰিবলৈ পূর্বনির্ধাৰণ কৰা হৈছে। পৰৱৰ্তী কল: সীমিত কৰা হোৱা নাই"</string>
+ <string name="serviceNotProvisioned" msgid="8614830180508686666">"সুবিধা যোগান ধৰা হোৱা নাই।"</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"আপুনি কলাৰ আইডি ছেটিং সলনি কৰিব নোৱাৰে।"</string>
+ <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"কোনো ডেটা সেৱা নাই"</string>
+ <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"জৰুৰীকালীন কল অৱৰোধিত কৰা হৈছে"</string>
+ <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"কোনো ভইচ সেৱা নাই"</string>
+ <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"কোনো ভইচ/জৰুৰীকালীন সেৱা নাই"</string>
+ <string name="RestrictedStateContent" msgid="4278821484643362350">"আপোনাৰ এলেকাত সাময়িকভাৱে ম\'বাইল নেটৱৰ্কটোৱে যোগান ধৰা নাই"</string>
+ <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"নেটৱর্ক পাব পৰা নাই"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="7056776609127756440">"বেতাঁৰ সম্প্ৰচাৰ লাভৰ মান উন্নত কৰিবলৈ, ছেটিংসমূহ > নেটৱৰ্ক আৰু ইণ্টাৰনেট > ম\'বাইল নেটৱৰ্কসমূহ > পচন্দৰ নেটৱৰ্কৰ প্ৰকাৰ-লৈ গৈ বাছনি কৰি থোৱা নেটৱৰ্কৰ প্ৰকাৰটো সলনি কৰি চাওক।"</string>
+ <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ৱাই-ফাই কলিং সক্ৰিয় হৈ আছে"</string>
+ <string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"জৰুৰীকালীন কল কৰিবলৈ নেটৱৰ্কৰ প্ৰয়োজন।"</string>
+ <string name="notification_channel_network_alert" msgid="4427736684338074967">"সতৰ্কবাণীসমূহ"</string>
+ <string name="notification_channel_call_forward" msgid="2419697808481833249">"কল ফৰৱাৰ্ডিং"</string>
+ <string name="notification_channel_emergency_callback" msgid="6686166232265733921">"জৰুৰীকালীন ক\'লবেক ম\'ড"</string>
+ <string name="notification_channel_mobile_data_status" msgid="4575131690860945836">"ম\'বাইল ডেটাৰ স্থিতি"</string>
+ <string name="notification_channel_sms" msgid="3441746047346135073">"এছএমএছ বার্তাবোৰ"</string>
+ <string name="notification_channel_voice_mail" msgid="3954099424160511919">"ভইচমেইলৰ বাৰ্তাসমূহ"</string>
+ <string name="notification_channel_wfc" msgid="2130802501654254801">"ৱাই-ফাই কলিং"</string>
+ <!-- no translation found for notification_channel_sim (4052095493875188564) -->
+ <skip />
+ <string name="peerTtyModeFull" msgid="6165351790010341421">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড FULLলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
+ <string name="peerTtyModeHco" msgid="5728602160669216784">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
+ <string name="peerTtyModeVco" msgid="1742404978686538049">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
+ <string name="peerTtyModeOff" msgid="3280819717850602205">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড OFFলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
+ <string name="serviceClassVoice" msgid="1258393812335258019">"কণ্ঠস্বৰ"</string>
+ <string name="serviceClassData" msgid="872456782077937893">"ডেটা"</string>
+ <string name="serviceClassFAX" msgid="5566624998840486475">"ফেক্স"</string>
+ <string name="serviceClassSMS" msgid="2015460373701527489">"এছএমএছ"</string>
+ <string name="serviceClassDataAsync" msgid="4523454783498551468">"এছিংক"</string>
+ <string name="serviceClassDataSync" msgid="7530000519646054776">"ছিংক"</string>
+ <string name="serviceClassPacket" msgid="6991006557993423453">"পেকেট"</string>
+ <string name="serviceClassPAD" msgid="3235259085648271037">"পেড"</string>
+ <string name="roamingText0" msgid="7170335472198694945">"ৰ\'মিঙৰ সূচক অন হৈ আছে"</string>
+ <string name="roamingText1" msgid="5314861519752538922">"ৰ\'মিঙৰ সূচক অফ আছে"</string>
+ <string name="roamingText2" msgid="8969929049081268115">"ৰ\'মিঙৰ সূচক জিলিকি আছে"</string>
+ <string name="roamingText3" msgid="5148255027043943317">"চুবুৰিৰ বাহিৰত"</string>
+ <string name="roamingText4" msgid="8808456682550796530">"বিল্ডিঙৰ বাহিৰত"</string>
+ <string name="roamingText5" msgid="7604063252850354350">"ৰ\'মিং - পচন্দৰ ছিষ্টেম"</string>
+ <string name="roamingText6" msgid="2059440825782871513">"ৰ\'মিং- উপলব্ধ ছিষ্টেম"</string>
+ <string name="roamingText7" msgid="7112078724097233605">"ৰ\'মিং - মিত্ৰ-গোষ্ঠীৰ অংশীদাৰ"</string>
+ <string name="roamingText8" msgid="5989569778604089291">"ৰ\'মিং- প্ৰিমিয়াম অংশীদাৰ"</string>
+ <string name="roamingText9" msgid="7969296811355152491">"ৰ\'মিং - সেৱা সম্পূর্ণভাৱে কৰ্মক্ষম"</string>
+ <string name="roamingText10" msgid="3992906999815316417">"ৰ\'মিং - সেৱা আংশীকভাৱে কৰ্মক্ষম"</string>
+ <string name="roamingText11" msgid="4154476854426920970">"ৰ\'মিঙৰ বেনাৰ অন অৱস্থাত আছে"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"ৰ\'মিঙৰ বেনাৰ অফ অৱস্থাত আছে"</string>
+ <string name="roamingTextSearching" msgid="8360141885972279963">"সেৱাৰ বাবে অনুসন্ধান কৰি থকা হৈছে"</string>
+ <!-- no translation found for wfcRegErrorTitle (2301376280632110664) -->
+ <skip />
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="3910386316304772394">"ৱাই-ফাইৰ জৰিয়তে কল কৰিবলৈ আৰু বাৰ্তা পঠাবলৈ, প্ৰথমে আপোনাৰ বাহকক আপোনাৰ ডিভাইচটো ছেট আপ কৰিব দিবলৈ কওক। তাৰ পিচত, ছেটিংসমূহলৈ গৈ আকৌ ৱাই-ফাই কলিং অন কৰক। (ত্ৰুটি ক\'ড: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ </string-array>
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item msgid="7472393097168811593">"আপোনাৰ বাহকৰ ওচৰত পঞ্জীয়ন কৰক (ত্ৰুটি ক\'ড: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ </string-array>
+ <string-array name="wfcSpnFormats">
+ <item msgid="6830082633573257149">"%s"</item>
+ <item msgid="4397097370387921767">"%s ৱাই- ফাই কলিং"</item>
+ </string-array>
+ <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+ <skip />
+ <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+ <skip />
+ <string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ম\'বাইলক অগ্ৰাধিকাৰ দিয়া হৈছে"</string>
+ <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+ <skip />
+ <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফৰৱাৰ্ড কৰা নহ\'ল"</string>
+ <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ছেকেণ্ডৰ পাছত"</string>
+ <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফৰৱাৰ্ড কৰা নহ\'ল"</string>
+ <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফৰৱাৰ্ড কৰা নহ\'ল"</string>
+ <string name="fcComplete" msgid="3118848230966886575">"সুবিধাৰ ক\'ড সম্পূর্ণ হ\'ল।"</string>
+ <string name="fcError" msgid="3327560126588500777">"সংযোগত সমস্যা হৈছে বা সুবিধাৰ ক\'ড অমান্য।"</string>
+ <string name="httpErrorOk" msgid="1191919378083472204">"ঠিক আছে"</string>
+ <string name="httpError" msgid="7956392511146698522">"ইণ্টাৰনেট সম্পর্কীয় আসোঁৱাহ হ\'ল৷"</string>
+ <string name="httpErrorLookup" msgid="4711687456111963163">"URL বিচাৰি পোৱা নগ\'ল।"</string>
+ <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"ছাইট সত্যাপন আঁচনিটো সমৰ্থিত নহয়৷"</string>
+ <string name="httpErrorAuth" msgid="1435065629438044534">"বিশ্বাসযোগ্যতাৰ প্ৰমাণ কৰিব পৰা নগ\'ল।"</string>
+ <string name="httpErrorProxyAuth" msgid="1788207010559081331">"প্ৰ\'ক্সী ছার্ভাৰৰ জৰিয়তে বিশ্বাসযোগ্যতা প্ৰমাণ কৰিব পৰা নগ\'ল।"</string>
+ <string name="httpErrorConnect" msgid="8714273236364640549">"ছার্ভাৰত সংযোগ কৰিব পৰা নগ\'ল।"</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"ছার্ভাৰৰ সৈতে যোগাযোগ কৰিব পৰা নগ\'ল। আকৌ চেষ্টা কৰক।"</string>
+ <string name="httpErrorTimeout" msgid="4743403703762883954">"ছার্ভাৰৰ লগত সংযোগৰ চেষ্টাৰ সময়সীমা উকলিল৷"</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"এই পৃষ্টাটোত অত্যধিক ছাৰ্ভাৰ ৰিডাইৰেক্ট আছে।"</string>
+ <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"ছাৰ্ভাৰৰ প্ৰ\'ট\'কল সমৰ্থিত নহয়৷"</string>
+ <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"এটা সুৰক্ষিত সংযোগ স্থাপন কৰিব পৰা নগ\'ল।"</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"অমান্য URLৰ বাবে পৃষ্ঠাটো খুলিব পৰা নগ\'ল।"</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"ফাইলত খুলিব পৰা নগ\'ল।"</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"অনুৰোধ কৰা ফাইলটো বিচাৰি পোৱা নগ\'ল।"</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"বহুত বেছি অনুৰোধৰ প্ৰক্ৰিয়া চলি আছে৷ অনুগ্ৰহ কৰি পিছত আকৌ চেষ্টা কৰক৷"</string>
+ <string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g>ত ছাইন ইন কৰাত আসোঁৱাহ"</string>
+ <string name="contentServiceSync" msgid="8353523060269335667">"ছিংক ত্ৰুটি"</string>
+ <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ছিংক ত্ৰুটি"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"বহুতো <xliff:g id="CONTENT_TYPE">%s</xliff:g> একেলগে মচা হৈছে।"</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"টেবলেটৰ সঞ্চয়াগাৰত খালী ঠাই নাই। ঠাই খালী কৰিবলৈ কিছুমান ফাইল মচক।"</string>
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"ঘড়ীৰ সঞ্চয়াগাৰ ভৰি পৰিছে। খালী স্থান উলিয়াবলৈ কিছুমান ফাইল মচক।"</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"টিভিৰ সঞ্চয়াগাৰ ভৰি পৰিছে। খালী ঠাই উলিয়াবলৈ কিছুমান ফাইল মচক।"</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"ফ\'নৰ সঞ্চয়াগাৰত খালী ঠাই নাই। ঠাই খালী কৰিবলৈ কিছুমান ফাইল মচক।"</string>
+ <plurals name="ssl_ca_cert_warning" formatted="false" msgid="5106721205300213569">
+ <item quantity="one">প্ৰমাণপত্ৰ প্ৰদানকাৰী কৰ্তৃপক্ষ ইনষ্টল কৰা হ\'ল</item>
+ <item quantity="other">প্ৰমাণপত্ৰ প্ৰদানকাৰী কৰ্তৃপক্ষ ইনষ্টল কৰা হ\'ল</item>
+ </plurals>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"এটা অজ্ঞাত তৃতীয় পক্ষৰদ্বাৰা"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="3541729986326153557">"আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ প্ৰশাসকে পৰ্যবেক্ষণ কৰি আছে"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>ৰ দ্বাৰা"</string>
+ <string name="work_profile_deleted" msgid="5005572078641980632">"কৰ্মস্থানৰ প্ৰ\'ফাইল মচা হ\'ল"</string>
+ <string name="work_profile_deleted_description" msgid="1100529432509639864">"প্ৰশাসক এপ্ নথকাৰ বাবে কৰ্মস্থানৰ প্ৰ\'ফাইল মচা হ\'ল"</string>
+ <string name="work_profile_deleted_details" msgid="6307630639269092360">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ প্ৰশাসক এপ্ নাই বা ব্যৱহাৰযোগ্য হৈ থকা নাই। যাৰ ফলত আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল আৰু ইয়াৰ লগত জড়িত অন্য ডেটাসমূহ মচা হৈছে। সহায়ৰ বাবে আপোনাৰ প্ৰশাসকৰ সৈতে সম্পর্ক কৰক।"</string>
+ <string name="work_profile_deleted_description_dpm_wipe" msgid="8823792115612348820">"আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল এই ডিভাইচটোত আৰু উপলব্ধ নহয়"</string>
+ <string name="work_profile_deleted_reason_maximum_password_failure" msgid="8986903510053359694">"বহুতবাৰ ভুলকৈ পাছৱৰ্ড দিয়া হৈছে"</string>
+ <string name="network_logging_notification_title" msgid="6399790108123704477">"পৰিচালিত ডিভাইচ"</string>
+ <string name="network_logging_notification_text" msgid="7930089249949354026">"আপোনাৰ প্ৰতিষ্ঠানটোৱে এই ডিভাইচটো পৰিচালনা কৰে আৰু ই নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে। সবিশেষ জানিবলৈ টিপক।"</string>
+ <string name="factory_reset_warning" msgid="5423253125642394387">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string>
+ <!-- no translation found for factory_reset_message (9024647691106150160) -->
+ <skip />
+ <!-- no translation found for printing_disabled_by (8936832919072486965) -->
+ <skip />
+ <string name="me" msgid="6545696007631404292">"মই"</string>
+ <string name="power_dialog" product="tablet" msgid="8545351420865202853">"টে\'বলেটৰ বিকল্পসমূহ"</string>
+ <string name="power_dialog" product="tv" msgid="6153888706430556356">"টিভিৰ বিকল্পসমূহ"</string>
+ <string name="power_dialog" product="default" msgid="1319919075463988638">"ফ\'নৰ বিকল্পসমূহ"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"নিঃশব্দ ম\'ড"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"ৱায়াৰলেছ অন কৰক"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"ৱায়াৰলেছ অফ কৰক"</string>
+ <string name="screen_lock" msgid="799094655496098153">"স্ক্ৰীণ লক"</string>
+ <string name="power_off" msgid="4266614107412865048">"পাৱাৰ অফ"</string>
+ <string name="silent_mode_silent" msgid="319298163018473078">"ৰিংগাৰ অফ আছে"</string>
+ <string name="silent_mode_vibrate" msgid="7072043388581551395">"ৰিংগাৰ কম্পন অৱস্থাত আছে"</string>
+ <string name="silent_mode_ring" msgid="8592241816194074353">"ৰিংগাৰ অন আছে"</string>
+ <string name="reboot_to_update_title" msgid="6212636802536823850">"Android ছিষ্টেমৰ আপডেট"</string>
+ <string name="reboot_to_update_prepare" msgid="6305853831955310890">"আপডেট সাজু কৰি থকা হৈছে…"</string>
+ <string name="reboot_to_update_package" msgid="3871302324500927291">"পেকেজ আপডেট কৰা প্ৰক্ৰিয়া চলি আছে…"</string>
+ <string name="reboot_to_update_reboot" msgid="6428441000951565185">"ৰিষ্টাৰ্ট কৰা হৈছে…"</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"ফেক্টৰী ডেটা ৰিছেট কৰক"</string>
+ <!-- no translation found for reboot_to_reset_message (2432077491101416345) -->
+ <skip />
+ <string name="shutdown_progress" msgid="2281079257329981203">"বন্ধ কৰি থকা হৈছে…"</string>
+ <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"আপোনাৰ টে\'বলেটটো বন্ধ হ\'ব।"</string>
+ <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"আপোনাৰ টিভি বন্ধ কৰা হ\'ব৷"</string>
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"আপোনাৰ ঘড়ী বন্ধ কৰা হ\'ব।"</string>
+ <string name="shutdown_confirm" product="default" msgid="649792175242821353">"আপোনাৰ ফ\'নটো বন্ধ হ\'ব।"</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"আপুনি ফ\'নটোৰ পাৱাৰ অফ কৰিব বিচাৰেনে?"</string>
+ <string name="reboot_safemode_title" msgid="7054509914500140361">"সুৰক্ষিত ম\'ডলৈ ৰিবুট কৰক"</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"আপুনি সুৰক্ষিত ম\'ডলৈ ৰিবুট কৰিব বিচাৰেনে? এই কার্যই আপুনি ইনষ্টল কৰা তৃতীয় পক্ষৰ সকলো এপ্লিকেশ্বন অক্ষম কৰিব। আপুনি পুনৰ ৰিবুট কৰিলে সেইবোৰ পুনঃস্থাপন কৰা হ\'ব।"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"শেহতীয়া"</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"কোনো শেহতীয়া এপ্ নাই।"</string>
+ <string name="global_actions" product="tablet" msgid="408477140088053665">"টে\'বলেটৰ বিকল্পসমূহ"</string>
+ <string name="global_actions" product="tv" msgid="7240386462508182976">"টিভিৰ বিকল্পসমূহ"</string>
+ <string name="global_actions" product="default" msgid="2406416831541615258">"ফ\'নৰ বিকল্পসমূহ"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"স্ক্ৰীণ ল\'ক"</string>
+ <string name="global_action_power_off" msgid="4471879440839879722">"পাৱাৰ অফ"</string>
+ <string name="global_action_emergency" msgid="7112311161137421166">"জৰুৰীকালীন কল"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"বাগ সম্পর্কীয় অভিযোগ"</string>
+ <string name="global_action_logout" msgid="935179188218826050">"ছেশ্বন সমাপ্ত কৰক"</string>
+ <!-- no translation found for global_action_screenshot (8329831278085426283) -->
+ <skip />
+ <string name="bugreport_title" msgid="2667494803742548533">"বাগ সম্পর্কীয় অভিযোগ লওক"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"এই কার্যই ইমেইল বাৰ্তা হিচাপে পঠিয়াবলৈ আপোনাৰ ডিভাইচৰ বৰ্তমান অৱস্থাৰ বিষয়ে তথ্য সংগ্ৰহ কৰিব৷ ইয়াক বাগ সম্পর্কীয় অভিযোগ পঠিওৱা কাৰ্য আৰম্ভ কৰোঁতে অলপ সময় লাগিব; অনুগ্ৰহ কৰি ধৈৰ্য ধৰক।"</string>
+ <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ইণ্টাৰেক্টিভ অভিযোগ"</string>
+ <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"বেছিভাগ পৰিস্থিতিত এয়া ব্যৱহাৰ কৰক। ই আপোনাক অভিযোগৰ অগ্ৰগতি ট্ৰেক কৰিবলৈ, সমস্যাটোৰ সম্পর্কে অধিক বিৱৰণ দিবলৈ আৰু স্ক্ৰীণশ্বট ল\'বলৈ অনুমতি দিয়ে। ই কম ব্যৱহাৰ হোৱা সেই শাখাসমূহক অন্তৰ্ভুক্ত নকৰিব পাৰে যিবোৰক অভিযোগ কৰিবলৈ দীৰ্ঘ সময়ৰ প্ৰয়োজন হয়।"</string>
+ <string name="bugreport_option_full_title" msgid="6354382025840076439">"সম্পূৰ্ণ অভিযোগ"</string>
+ <string name="bugreport_option_full_summary" msgid="7210859858969115745">"যেতিয়া আপোনাৰ ডিভাইচটোৱে সঁহাৰি নিদিয়া হয় বা ই অতি লেহেমীয়া হৈ পৰে বা যেতিয়া আপোনাক সকলো অভিযোগৰ শাখাৰ প্ৰয়োজন হয় তেতিয়া ছিষ্টেমত কম হস্তক্ষেপৰ বাবে এই বিকল্প ব্যৱহাৰ কৰক। আপোনাক অধিক বিৱৰণ দিবলৈ বা অতিৰিক্ত স্ক্ৰীণশ্বট ল’বলৈ নিদিয়ে।"</string>
+ <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+ <item quantity="one">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item>
+ <item quantity="other">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item>
+ </plurals>
+ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"নিঃশব্দ ম\'ড"</string>
+ <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ধ্বনি অফ আছে"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"ধ্বনি অন আছে"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"এয়াৰপ্লেইন ম\'ড"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"এয়াৰপ্লেইন ম\'ড অন কৰা আছে"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"এয়াৰপ্লেইন ম\'ড অফ কৰা আছে"</string>
+ <!-- no translation found for global_action_toggle_battery_saver (708515500418994208) -->
+ <skip />
+ <!-- no translation found for global_action_battery_saver_on_status (484059130698197787) -->
+ <skip />
+ <!-- no translation found for global_action_battery_saver_off_status (75550964969478405) -->
+ <skip />
+ <string name="global_action_settings" msgid="1756531602592545966">"ছেটিংসমূহ"</string>
+ <!-- no translation found for global_action_assist (3892832961594295030) -->
+ <skip />
+ <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
+ <skip />
+ <!-- no translation found for global_action_lockdown (1099326950891078929) -->
+ <skip />
+ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
+ <string name="notification_hidden_text" msgid="6351207030447943784">"নতুন জাননী"</string>
+ <string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"ভাৰ্শ্বুৱল কীব\'ৰ্ড"</string>
+ <string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"কায়িক কীব’ৰ্ড"</string>
+ <string name="notification_channel_security" msgid="7345516133431326347">"সুৰক্ষা"</string>
+ <string name="notification_channel_car_mode" msgid="3553380307619874564">"গাড়ী ম\'ড"</string>
+ <string name="notification_channel_account" msgid="7577959168463122027">"একাউণ্টৰ স্থিতি"</string>
+ <string name="notification_channel_developer" msgid="7579606426860206060">"বিকাশকৰ্তাৰ বাৰ্তাসমূহ"</string>
+ <string name="notification_channel_updates" msgid="4794517569035110397">"আপডেটবোৰ"</string>
+ <string name="notification_channel_network_status" msgid="5025648583129035447">"নেটৱৰ্কৰ স্থিতি"</string>
+ <string name="notification_channel_network_alerts" msgid="2895141221414156525">"নেটৱৰ্ক সম্পৰ্কীয় সতৰ্কবাণী"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"নেটৱৰ্ক উপলব্ধ"</string>
+ <string name="notification_channel_vpn" msgid="8330103431055860618">"ভিপিএনৰ স্থিতি"</string>
+ <string name="notification_channel_device_admin" msgid="1568154104368069249">"ডিভাইচৰ প্ৰশাসন"</string>
+ <string name="notification_channel_alerts" msgid="4496839309318519037">"সতৰ্কবাণীসমূহ"</string>
+ <string name="notification_channel_retail_mode" msgid="6088920674914038779">"খুচুৰা ডেম\'"</string>
+ <string name="notification_channel_usb" msgid="9006850475328924681">"ইউএছবি সংযোগ"</string>
+ <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"এপ্ চলি আছে"</string>
+ <string name="notification_channel_foreground_service" msgid="3931987440602669158">"বেটাৰি খৰচ কৰা এপসমূহ"</string>
+ <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বেটাৰি ব্যৱহাৰ কৰি আছে"</string>
+ <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g>টা এপে বেটাৰি ব্যৱহাৰ কৰি আছে"</string>
+ <string name="foreground_service_tap_for_details" msgid="372046743534354644">"বেটাৰি আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে বিশদভাৱে জানিবলৈ টিপক"</string>
+ <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
+ <string name="safeMode" msgid="2788228061547930246">"সুৰক্ষিত ম\'ড"</string>
+ <string name="android_system_label" msgid="6577375335728551336">"Android ছিষ্টেম"</string>
+ <!-- no translation found for user_owner_label (8836124313744349203) -->
+ <skip />
+ <!-- no translation found for managed_profile_label (8947929265267690522) -->
+ <skip />
+ <!-- no translation found for permgrouplab_contacts (3657758145679177612) -->
+ <skip />
+ <!-- no translation found for permgroupdesc_contacts (6951499528303668046) -->
+ <skip />
+ <string name="permgrouprequest_contacts" msgid="1601591667800538208">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ সম্পৰ্কসূচী চাবলৈ অনুমতি দিয়ক"</string>
+ <!-- no translation found for permgrouplab_location (7275582855722310164) -->
+ <skip />
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"এই ডিভাইচৰ অৱস্থান ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permgrouprequest_location" msgid="8903573681261610809">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক ডিভাইচৰ অৱস্থান জানিবলৈ অনুমতি দিয়ক"</string>
+ <string name="permgrouplab_calendar" msgid="5863508437783683902">"কেলেণ্ডাৰ"</string>
+ <!-- no translation found for permgroupdesc_calendar (3889615280211184106) -->
+ <skip />
+ <string name="permgrouprequest_calendar" msgid="6704529828699071445">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ কেলেণ্ডাৰ চাবলৈ অনুমতি দিয়ক"</string>
+ <!-- no translation found for permgrouplab_sms (228308803364967808) -->
+ <skip />
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"এছএমএছ বার্তা পঠিয়াব আৰু চাব পাৰে"</string>
+ <string name="permgrouprequest_sms" msgid="605618939583628306">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক এছএমএছ বাৰ্তা পঠিয়াবলৈ আৰু চাবলৈ অনুমতি দিয়ক"</string>
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"সঞ্চয়াগাৰ"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"আপোনাৰ ডিভাইচৰ ফট\', মিডিয়া আৰু ফাইলসমূহ ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permgrouprequest_storage" msgid="7429669910547860218">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ ডিভাইচত থকা ফট\', মিডিয়া আৰু ফাইল চাবলৈ অনুমতি দিয়ক"</string>
+ <string name="permgrouplab_microphone" msgid="171539900250043464">"মাইক্ৰ\'ফ\'ন"</string>
+ <!-- no translation found for permgroupdesc_microphone (4988812113943554584) -->
+ <skip />
+ <string name="permgrouprequest_microphone" msgid="8065941268709600606">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক অডিঅ\' ৰেকৰ্ড কৰিবলৈ অনুমতি দিয়ক"</string>
+ <string name="permgrouplab_camera" msgid="4820372495894586615">"কেমেৰা"</string>
+ <!-- no translation found for permgroupdesc_camera (3250611594678347720) -->
+ <skip />
+ <string name="permgrouprequest_camera" msgid="810824326507258410">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক ছবি তুলিবলৈ আৰু ভিডিঅ\' ৰেকৰ্ড কৰিবলৈ অনুমতি দিয়ক"</string>
+ <!-- no translation found for permgrouplab_phone (5229115638567440675) -->
+ <skip />
+ <!-- no translation found for permgroupdesc_phone (6234224354060641055) -->
+ <skip />
+ <string name="permgrouprequest_phone" msgid="7084161459732093690">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক ফ\'ন কল কৰিবলৈ আৰু পৰিচালনা কৰিবলৈ অনুমতি দিয়ক"</string>
+ <string name="permgrouplab_sensors" msgid="416037179223226722">"শৰীৰৰ ছেন্সৰসমূহ"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটা লাভ কৰিব পাৰে"</string>
+ <string name="permgrouprequest_sensors" msgid="8631146669524259656">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ক আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটা লাভ কৰিবলৈ অনুমতি দিয়ক"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"ৱিণ্ড\' সমল বিচাৰি উলিয়াওক"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"আপুনি যোগাযোগ কৰি থকা ৱিণ্ড\'খনৰ সমল পৰীক্ষা কৰক।"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"স্পৰ্শৰদ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰক"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"টেপ কৰা বস্তুসমূহ ডাঙৰকৈ কোৱা হ\'ব আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ দি স্ক্ৰীণ অন্বেষণ কৰিব পাৰিব।"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"আপুনি লিখা পাঠ নিৰীক্ষণ কৰক"</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ক্ৰেডিট কাৰ্ডৰ নম্বৰ আৰু পাছৱৰ্ডৰ দৰে ব্যক্তিগত ডেটা অন্তৰ্ভুক্ত হ\'ব পাৰে।"</string>
+ <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ডিছপ্লেৰ বিবৰ্ধন নিয়ন্ত্ৰণ কৰক"</string>
+ <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ডিছপ্লেৰ জুমৰ স্তৰ আৰু অৱস্থান নিয়ন্ত্ৰণ কৰক।"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ কৰা কার্যসমূহ কৰক"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"টেপ কৰা, ছোৱাইপ কৰা, পিঞ্চ কৰা আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ কৰা অন্যান্য কাৰ্যসমূহ কৰিব পাৰে।"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"ফিংগাৰপ্ৰিণ্ট নিৰ্দেশসমূহ"</string>
+ <!-- no translation found for capability_desc_canCaptureFingerprintGestures (4386487962402228670) -->
+ <skip />
+ <string name="permlab_statusBar" msgid="7417192629601890791">"স্থিতি দণ্ড অক্ষম কৰক বা সলনি কৰক"</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"স্থিতি দণ্ড অক্ষম কৰিবলৈ বা ছিষ্টেম আইকন আঁতৰাবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_statusBarService" msgid="4826835508226139688">"স্থিতি দণ্ড হ\'ব পাৰে"</string>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"নিজকে স্থিতি দণ্ডৰূপে দেখুওৱাবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_expandStatusBar" msgid="1148198785937489264">"স্থিতি দণ্ড সম্প্ৰসাৰিত বা সংকোচিত কৰক"</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"স্থিতি দণ্ড বিস্তাৰিত বা সংকুচিত কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_install_shortcut" msgid="4279070216371564234">"শ্বৰ্টকাট ইনষ্টল কৰিব পাৰে"</string>
+ <string name="permdesc_install_shortcut" msgid="8341295916286736996">"এটা এপ্লিকেশ্বনক ব্যৱহাৰকাৰীৰ হস্তক্ষেপৰ অবিহনে গৃহ স্ক্ৰীণ শ্বৰ্টকাট যোগ কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"শ্বৰ্টকাট আনইনষ্টল কৰিব পাৰে"</string>
+ <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ব্যৱহাৰকাৰীৰ হস্তক্ষেপৰ অবিহনে গৃহ স্ক্ৰীণৰ শ্বৰ্টকাটসমূহ আঁতৰাবলৈ এপ্লিকেশ্বনক অনুমতি দিয়ে।"</string>
+ <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"বহিৰ্গামী কলসমূহ অন্য ক\'ৰবালৈ পঠিয়াওক"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"এটা বৰ্হিগামী কল কৰি থকাৰ সময়ত ডায়েল কৰা নম্বৰ চাবলৈ আৰু লগতে এটা পৃথক নম্বৰলৈ কল সংযোগ কৰিবলৈ বা সকলোকে একেলগে বন্ধ কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"ফ\'ন কলৰ উত্তৰ দিব পাৰে"</string>
+ <string name="permdesc_answerPhoneCalls" msgid="2901889867993572266">"এপটোক অন্তৰ্গামী ফ\'ন কলৰ উত্তৰ দিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_receiveSms" msgid="8673471768947895082">"পাঠ বার্তা (এছএমএছ) বোৰ লাভ কৰক"</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"এপটোক এছএমএছ বাৰ্তাবোৰ পাবলৈ আৰু প্ৰক্ৰিয়া সম্পন্ন কৰিবলৈ অনুমতি দিয়ে৷ ইয়াৰ অৰ্থ এইটোৱেই যে এপটোৱে আপোনাক বাৰ্তাবোৰ নেদেখুৱাকৈয়ে আপোনাৰ ডিভাইচলৈ পঠিওৱা বাৰ্তাবোৰ নিৰীক্ষণ কৰিব বা মচিব পাৰে৷"</string>
+ <string name="permlab_receiveMms" msgid="1821317344668257098">"পাঠ বার্তা (এমএমএছ) বোৰ লাভ কৰক"</string>
+ <string name="permdesc_receiveMms" msgid="533019437263212260">"এমএমএছ বার্তাবোৰ লাভ আৰু ইয়াৰ প্ৰক্ৰিয়া সম্পন্ন কৰিবলৈ এপক অনুমতি দিয়ে। ইয়াৰ অৰ্থ হৈছে এই এপে আপোনাৰ ডিভাইচলৈ প্ৰেৰণ কৰা বার্তাসমূহ আপোনাক নেদেখুৱাকৈয়ে পৰ্যবেক্ষণ আৰু মচিব পাৰে।"</string>
+ <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"চেল সম্প্ৰচাৰৰ বার্তাবোৰ পঢ়ক"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"আপোনাৰ ডিভাইচে লাভ কৰা চেল সম্প্ৰচাৰৰ বার্তাবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। আপোনাক জৰুৰীকালীন পৰিস্থিতিবোৰত সর্তক কৰিবলৈ চেল সম্প্ৰচাৰৰ বার্তাবোৰ প্ৰেৰণ কৰা হয়। জৰুৰীকালীন চেল সম্প্ৰচাৰ লাভ কৰাৰ সময়ত আপোনাৰ ডিভাইচৰ কাৰ্যদক্ষতা বা কাৰ্যপ্ৰণালীত ক্ষতিকাৰক এপবোৰে হস্তক্ষেপ কৰিব পাৰে।"</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"আপুনি সদস্যভুক্ত হোৱা ফীডসমূহ পঢ়ক"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"বৰ্তমান ছিংক কৰা ফীডৰ সবিশেষ লাভ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <!-- no translation found for permlab_sendSms (7544599214260982981) -->
+ <skip />
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"এপটোক এছএমএছ বাৰ্তা পঠিয়াবলৈ অনুমতি দিয়ে৷ ইয়াৰ ফলত অপ্ৰত্যাশিত মাচুল ভৰিবলগা হ\'ব পাৰে৷ ক্ষতিকাৰক এপসমূহে আপোনাৰ অনুমতি নোলোৱাকৈয়ে বাৰ্তা পঠিয়াই আপোনাৰ পৰা মাচুল কাটিব পাৰে৷"</string>
+ <string name="permlab_readSms" msgid="8745086572213270480">"আপোনাৰ পাঠ বার্তাবোৰ পঢ়ক (এছএমএছ বা এমএমএছ)"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"এই এপটোৱে আপোনাৰ টেবলেটটোত সংৰক্ষিত সকলো এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
+ <string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"এই এপটোৱে আপোনাৰ টিভিটোত সংৰক্ষিত সকলো এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
+ <string name="permdesc_readSms" product="default" msgid="6826832415656437652">"এই এপটোৱে আপোনাৰ ফ\'নত সংৰক্ষিত সকলো এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
+ <string name="permlab_receiveWapPush" msgid="5991398711936590410">"পাঠ বার্তা (WAP) বোৰ লাভ কৰক"</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"এপটোক WAP বাৰ্তাবোৰ পাবলৈ আৰু প্ৰক্ৰিয়া সম্পন্ন কৰিবলৈ অনুমতি দিয়ে৷ এই অনুমতিত আপোনালৈ পঠিওৱা বাৰ্তাবোৰ আপোনাক নেদেখুৱাকৈয়ে নিৰীক্ষণ বা মচাৰ সক্ষমতা অন্তৰ্ভুক্ত থাকে৷"</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"চলি থকা এপসমূহ বিচাৰি উলিয়াওক"</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"এপটোক বৰ্তমানে আৰু শেহতীয়াভাৱে চলি থকা কাৰ্যসমূহৰ বিষয়ে তথ্য পুনৰুদ্ধাৰ কৰিবলৈ অনুমতি দিয়ে৷ এইটোৱে এপটোক ডিভাইচটোত কোনবোৰ এপ্লিকেশ্বন ব্যৱহাৰ হৈ আছে তাৰ বিষয়ে তথ্য বিচাৰি উলিয়াবলৈ অনুমতি দিব পাৰে৷"</string>
+ <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"প্ৰ\'ফাইল আৰু ডিভাইচৰ গৰাকীসকলক পৰিচালনা কৰিব পাৰে"</string>
+ <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
+ <skip />
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"চলি থকা এপসমূহক পুনৰাই ক্ৰমবদ্ধ কৰক"</string>
+ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"গতিবিধিক অগ্ৰভাগ আৰু নেপথ্যলৈ নিবলৈ এপক অনুমতি দিয়ে। এপে এই কার্য আপোনাৰ ইনপুট অবিহনেই কৰিব পাৰে।"</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"গাড়ীৰ ম\'ড সক্ষম কৰক"</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"গাড়ী ম\'ড সক্ষম কৰিবলৈ এপটোক অনুমতি দিয়ে৷"</string>
+ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"অন্য এপবোৰ বন্ধ কৰক"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"এপটোক অন্য এপসমূহৰ নেপথ্যৰ প্ৰক্ৰিয়াসমূহ শেষ কৰিবলৈ অনুমতি দিয়ে৷ এই কার্যৰ বাবে অন্য এপসমূহ চলাটো বন্ধ হ\'ব পাৰে৷"</string>
+ <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"এই এপটো অইন এপৰ ওপৰত প্ৰদৰ্শিত হ\'ব পাৰে"</string>
+ <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"এই এপটো অইন এপৰ ওপৰত বা স্ক্ৰীণৰ অইন অংশত প্ৰদৰ্শিত হ\'ব পাৰে। এই কাৰ্যই এপসমূহৰ স্বাভাৱিক কাৰ্যকলাপত ব্যাঘাত জন্মাব পাৰে আৰু অইন এপসমূহক স্ক্ৰীণত কেনেকৈ দেখা পোৱা যায় সেইটো সলনি কৰিব পাৰে।"</string>
+ <string name="permlab_runInBackground" msgid="7365290743781858803">"নেপথ্যত চলিব পাৰে"</string>
+ <string name="permdesc_runInBackground" msgid="7370142232209999824">"এই এপটো নেপথ্যত চলিব পাৰে। ইয়াৰ ফলত বেটাৰি সোনকালে শেষ হ\'ব পাৰে।"</string>
+ <string name="permlab_useDataInBackground" msgid="8694951340794341809">"নেপথ্যত ডেটা ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"এই এপটোৱে নেপথ্যত ডেটা ব্যৱহাৰ কৰিব পাৰে। ইয়াৰ ফলত ডেটা বেছি খৰছ হ\'ব পাৰে।"</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"এপক সদায়ে চলি থকা কৰক"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"মেম\'ৰিত নিজৰ বাবে প্ৰয়োজনীয় ঠাই পৃথক কৰিবলৈ এপক অনুমতি দিয়ে। এই কার্যই টেবলেটৰ কার্যক লেহেমীয়া কৰি অন্য এপবোৰৰ বাবে উপলব্ধ মেম\'ৰিক সীমাবদ্ধ কৰে।"</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"মেম\'ৰিত নিজৰ বাবে প্ৰয়োজনীয় ঠাই পৃথক কৰিবলৈ এপটোক অনুমতি দিয়ে। এই কার্যই অন্য এপবোৰৰ বাবে উপলব্ধ মেম\'ৰিক সীমাবদ্ধ কৰে যাৰ বাবে টিভিটো লেহেমীয়া হয়।"</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"মেম\'ৰিত নিজৰ বাবে প্ৰয়োজনীয় ঠাই পৃথক কৰিবলৈ এপক অনুমতি দিয়ে। এই কার্যই ফ\'নৰ কার্যক লেহেমীয়া কৰি অন্য এপবোৰৰ বাবে উপলব্ধ মেম\'ৰিক সীমাবদ্ধ কৰে।"</string>
+ <!-- no translation found for permlab_foregroundService (3310786367649133115) -->
+ <skip />
+ <!-- no translation found for permdesc_foregroundService (6471634326171344622) -->
+ <skip />
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"এপৰ সঞ্চয়াগাৰৰ খালী ঠাই হিচাপ কৰক"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"এপটোক ইয়াৰ ক\'ড, ডেটা আৰু কেশ্বৰ আকাৰ বিচাৰি উলিয়াবলৈ অনুমতি দিয়ে"</string>
+ <string name="permlab_writeSettings" msgid="2226195290955224730">"ছিষ্টেম ছেটিংসমূহ সংশোধন কৰক"</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"এপটোক ছিষ্টেমৰ ছেটিংসমূহৰ ডেটা সংশোধন কৰিবলৈ অনুমতি দিয়ে৷ ক্ষতিকাৰক এপসমূহে আপোনাৰ ছিষ্টেম কনফিগাৰেশ্বনক ক্ষতিগ্ৰস্ত কৰিব পাৰে৷"</string>
+ <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"আৰম্ভ হোৱাৰ সময়ত চলাওক"</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"ছিষ্টেমে বুট কৰা কাৰ্য সমাপ্ত কৰাৰ লগে লগে এপটোক নিজে নিজে আৰম্ভ হ\'বলৈ অনুমতি দিয়ে। ইয়াৰ ফলত ফ\'নটো ষ্টাৰ্ট হওতে বেছি সময়ৰ প্ৰয়োজন হ\'ব পাৰে, আৰু এপটো সদায় চলি থকাৰ কাৰণে ফ\'নটো সামগ্ৰিকভাৱে লেহেমীয়া হ\'ব পাৰে।"</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"ছিষ্টেমে বুটিং সমাপ্ত কৰাৰ লগে লগে এপটোক নিজে নিজে আৰম্ভ হ\'বলৈ অনুমতি দিয়ে। এই কাৰ্যটোৰ বাবে টিভিটো আৰম্ভ হ\'বলৈ দীৰ্ঘ সময়ৰ প্ৰয়োজন হ\'ব পাৰে আৰু সদায়ে ই চলি থকাৰ বাবে টে\'বলেটটো সামগ্ৰিকভাৱে লেহেমীয়া হৈ পৰিব পাৰে।"</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"ছিষ্টেমে বুট কৰা কাৰ্য সমাপ্ত কৰাৰ লগে লগে এপটোক নিজে নিজে আৰম্ভ হ\'বলৈ অনুমতি দিয়ে। ইয়াৰ ফলত ফ\'নটো ষ্টাৰ্ট হওতে বেছি সময়ৰ প্ৰয়োজন হ\'ব পাৰে, আৰু এপটো সদায় চলি থকাৰ কাৰণে ফ\'নটো সামগ্ৰিকভাৱে লেহেমীয়া হ\'ব পাৰে।"</string>
+ <string name="permlab_broadcastSticky" msgid="7919126372606881614">"ষ্টিকী ব্ৰ\'ডকাষ্ট পঠিয়াওক"</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"সম্প্ৰচাৰৰ শেষত বাকী ৰোৱা ষ্টিকী ব্ৰ\'ডকাষ্টবোৰ প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে। ইয়াক অত্য়ধিক ব্যৱহাৰ কৰাৰ ফলত মেম\'ৰি অধিক খৰচ হোৱাৰ বাবে টেবলেট লেহেমীয়া বা অস্থিৰ হৈ পৰে।"</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"এপটোক ষ্টিকী ব্ৰ\'ডকাষ্ট প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে, যিবোৰ সম্প্ৰচাৰ শেষ হোৱাৰ পিছতো ৰৈ যায়। ইয়াক অত্য়ধিক ব্যৱহাৰ কৰিলে মেম\'ৰি অধিক খৰচ হোৱাৰ বাবে টিভিটো লেহেমীয়া বা অস্থিৰ হৈ পৰিব পাৰে।"</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"সম্প্ৰচাৰৰ শেষত বাকী ৰোৱা ষ্টিকী ব্ৰ\'ডকাষ্টবোৰ প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে। ইয়াক অত্য়ধিক ব্যৱহাৰ কৰাৰ ফলত মেম\'ৰি অধিক খৰচ হোৱাৰ বাবে ফ\'নটো লেহেমীয়া বা অস্থিৰ হৈ পৰে।"</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"নিজৰ সম্পর্ক সূচী পঢ়ক"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"আপুনি কোনো ব্যক্তি বিশেষৰ সৈতে টেবলেট, ইমেইল বা অন্য মাধ্যমেৰে কিমান সঘনাই যোগাযোগ কৰিছে সেই তথ্য়সহ ফ\'নৰ সম্পর্কসূচীত সঞ্চয় কৰা ডেটা পঢ়িবলৈ এপক অনুমতি দিয়ে৷ এই কার্যই এপক আপোনাৰ সম্পর্কৰ ডেটা ছেভ কৰিবলৈ অনুমতি দিয়ে আৰু ক্ষতিকাৰক এপবোৰে সম্পর্কসূচীৰ ডেটা আপোনাৰ অজ্ঞাতেই শ্বেয়াৰ কৰিব পাৰে৷"</string>
+ <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"এপটোক আপোনাৰ টিভিত জমা থকা সম্পৰ্কসমূৰ বিষয়ে থকা ডেটা পঢ়িবলৈ অনুমতি দিয়াৰ লগতে আপুনি কোনো বিশেষ ব্যক্তিৰ সৈতে কিমান সঘনাই কল, ইমেইল বা অন্য মাধ্যমেৰে যোগাযোগ কৰিছে তাকো জানিবলৈ সুযোগ দিয়ে। এই বিশেষ অনুমতিটোৰ বাবে এপটোৱে আপোনাৰ সম্পর্ক ডেটা ছেভ কৰিব পাৰে, আৰু ক্ষতিকাৰক এপবোৰে সম্পর্কসূচীৰ ডেটা আপুনি নজনাকৈ শ্বেয়াৰ কৰিব পাৰে৷"</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"আপুনি কোনো বিশেষ ব্যক্তিৰ সৈতে কিমান সঘনাই ফ\'ন, ইমেইল বা অন্য মাধ্যমেৰে যোগাযোগ কৰে সেই সম্পর্কে ফ\'নৰ সম্পর্ক সূচীত সঞ্চয় কৰা ডেটা পঢ়িবলৈ এপক অনুমতি দিয়ে। এই অনুমতিএ এপক আপোনাৰ সম্পর্কৰ ডেটা ছেভ কৰিবলৈ দিয়ে আৰু ক্ষতিকাৰক এপবোৰে সম্পর্কৰ ডেটা আপোনাৰ অজ্ঞাতেই শ্বেয়াৰ কৰিব পাৰে।"</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"আপোনাৰ সম্পর্ক সূচী সংশোধন কৰক"</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"আপুনি ব্য়ক্তি বিশেষক কিমান সঘনাই কল কৰিছে, ইমেইল কৰিছে বা অন্য উপায়েৰে যোগাযোগ কৰিছে তাক অন্তৰ্ভুক্ত কৰি এপটোক আপোনাৰ টেবলেটত সঞ্চয় কৰি ৰখা সম্পৰ্ক সূচীৰ ডেটা সংশোধন কৰিবলৈ অনুমতি দিয়ে৷ এই অনুমতি দিলে এপসমূহে সম্পৰ্কসূচীৰ ডেটা মচিব পাৰে।"</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"আপুনি যিসকল লোকক কল কৰিছে, ইমেইল কৰিছে বা সম্পৰ্কসূচীৰ বিশেষ লোকসকলৰ লগত অন্য উপায়েৰে যোগাযোগ কৰিছে তাক অন্তৰ্ভুক্ত কৰি এপটোক আপোনাৰ টিভিত সঞ্চয় কৰি ৰখা ডেটা সংশোধন কৰিবলৈ অনুমতি দিয়ে। এই অনুমতিয়ে এপসমূহক সম্পৰ্কসূচীৰ ডেটা মচি পেলাবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"আপুনি কোনো বিশেষ ব্যক্তিৰ সৈতে কিমান সঘনাই ফ\'ন, ইমেইল বা অন্য মাধ্যমেৰে যোগাযোগ কৰে সেই সম্পর্কে ফ\'নৰ সম্পর্ক সূচীত সঞ্চয় কৰা ডেটা পঢ়িবলৈ এপক অনুমতি দিয়ে। এই কার্যই এপক সম্পর্কৰ ডেটা মচিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_readCallLog" msgid="3478133184624102739">"কল লগ পঢ়ক"</string>
+ <string name="permdesc_readCallLog" msgid="3204122446463552146">"এই এপে আপোনাৰ কলৰ ইতিহাস পঢ়িব পাৰে।"</string>
+ <string name="permlab_writeCallLog" msgid="8552045664743499354">"কল লগ লিখক"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"অন্তৰ্গামী আৰু বহিৰ্গামী কলৰ ডেটাকে ধৰি আপোনাৰ টেবলেটৰ কল লগ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। ক্ষতিকাৰক এপবোৰে আপোনাৰ কল লগ মচিবলৈ বা সংশোধন কৰিবলৈ ইয়াক ব্যৱহাৰ কৰিব পাৰে।"</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"অন্তৰ্গামী আৰু বহিৰ্গামী কলৰ ডেটাকে ধৰি আপোনাৰ টিভিৰ কল লগ সংশোধন কৰিবলৈ এপটোক অনুমতি দিয়ক। ক্ষতিকাৰক এপ্বোৰে আপোনাৰ কল লগ মচিবলৈ বা সংশোধন কৰিবলৈ এয়া ব্যৱহাৰ কৰিব পাৰে।"</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"অন্তৰ্গামী আৰু বহিৰ্গামী কলৰ ডেটাকে ধৰি আপোনাৰ ফ\'নৰ কল লগ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। ক্ষতিকাৰক এপবোৰে আপোনাৰ কল লগ মচিবলৈ বা সংশোধন কৰিবলৈ ইয়াক ব্যৱহাৰ কৰিব পাৰে।"</string>
+ <string name="permlab_bodySensors" msgid="4683341291818520277">"শৰীৰৰ ছেন্সৰসমূহ (যেনে হৃদপিণ্ডৰ গতিৰ হাৰ নিৰীক্ষক) ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"আপোনাৰ হৃদস্পন্দনৰ দৰে শাৰীৰিক অৱস্থাক নিৰীক্ষণ কৰা ছেন্সৰৰ পৰা ডেটা লাভ কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_readCalendar" msgid="6716116972752441641">"কেলেণ্ডাৰৰ কাৰ্যক্ৰম আৰু সবিশেষ পঢ়িব পাৰে"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"এই এপটোৱে আপোনাৰ টেবলেটটোত সংৰক্ষিত সকলো কেলেণ্ডাৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"এই এপটোৱে আপোনাৰ টিভিটোত সংৰক্ষিত সকলো কেলেণ্ডাৰৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
+ <string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"এই এপটোৱে আপোনাৰ ফ\'নটোত সংৰক্ষিত সকলো কেলেণ্ডাৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"গৰাকীয়ে নজনাকৈয়ে কেলেণ্ডাৰৰ কাৰ্যক্ৰম সংশোধন কৰি অতিথিসকললৈ ইমেইল প্ৰেৰণ কৰক"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"এই এপটোৱে আপোনাৰ টেবলেটত কেলেণ্ডাৰ কাৰ্যক্ৰম যোগ কৰিব, আঁতৰাব বা সলনি কৰিব পাৰে। ই এনে বাৰ্তা পঠিয়াব পাৰে যিবোৰ কেলেণ্ডাৰৰ গৰাকীৰ পৰা অহা যেন লাগিব বা ই গৰাকীক নজনোৱাকৈ কাৰ্যক্ৰম সলনি কৰিব পাৰে৷"</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="9017809326268135866">"এই এপটোৱে আপোনাৰ টিভিত কেলেণ্ডাৰ কাৰ্যক্ৰম যোগ কৰিব, আঁতৰাব বা সলনি কৰিব পাৰে। এই এপে এনে বাৰ্তা পঠিয়াব পাৰে যিবোৰ কেলেণ্ডাৰৰ গৰাকীৰ পৰা অহা যেন লাগিব বা ই গৰাকীক নজনোৱাকৈ কাৰ্যক্ৰম সলনি কৰিব পাৰে৷"</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"এই এপে আপোনাৰ ফ\'নৰ কেলেণ্ডাৰত কার্যক্ৰম যোগ দিব, আঁতৰাব বা সলনি কৰিব পাৰে। ই এনে বাৰ্তা পঠিয়াব পাৰে যিবোৰ কেলেণ্ডাৰৰ গৰাকীৰ পৰা অহা যেন লাগে বা ই গৰাকীক নজনোৱাকৈ কাৰ্যক্ৰম সলনি কৰিব পাৰে৷"</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"অতিৰিক্ত অৱস্থান দেখুওৱা নির্দেশত প্ৰৱেশ কৰক"</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"অৱস্থানৰ অতিৰিক্ত নির্দেশনাসমূহত প্ৰৱেশ কৰিবলৈ এপক অনুমতি দিয়ে। ইয়ে এপটোক জিপিএছ বা অন্য অৱস্থান উৎসসমূহৰ কাৰ্যকলাপত হস্তক্ষেপ কৰাৰ সুযোগ দিব পাৰে।"</string>
+ <string name="permlab_accessFineLocation" msgid="251034415460950944">"সঠিক অৱস্থান (জিপিএছ আৰু নেটৱর্ক ভিত্তিক) ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permdesc_accessFineLocation" msgid="5821994817969957884">"এই এপটোৱে জিপিএছ বা নেটৱর্কৰ উৎসসমূহ যেনে চেল টাৱাৰ আৰু ৱাই-ফাই নেটৱর্ক আদিক ভিত্তি কৰি আপোনাৰ অৱস্থান নিৰ্ণয় কৰিব পাৰে। এই অৱস্থানৰ সেৱাসমূহ অন হৈ থাকিলে আৰু আপোনাৰ ফ\'নটোত উপলব্ধ হ\'লেহে এপটোৱে সেইবোৰ ব্যৱহাৰ কৰিবলৈ সক্ষম হ\'ব। এই কার্যই অধিক বেটাৰি খৰচ কৰিব পাৰে।"</string>
+ <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"অনুমানিক অৱস্থান (নেটৱর্ক ভিত্তিক) ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"চেল টাৱাৰ আৰু ৱাই-ফাই নেটৱর্কৰ দৰে নেটৱর্কৰ উৎসসমূহক ভিত্তি কৰি এই এপটোৱে আপোনাৰ অৱস্থান নিৰ্ণয় কৰিব পাৰে। এই অৱস্থানৰ সেৱাসমূহ অন হৈ থাকিলে আৰু আপোনাৰ টেবলেটটোত উপলব্ধ হ\'লেহে এপটোৱে সেইবোৰ ব্যৱহাৰ কৰিবলৈ সক্ষম হ\'ব।"</string>
+ <string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"চেল টাৱাৰ আৰু ৱাই-ফাই নেটৱর্কৰ দৰে নেটৱর্কৰ উৎসসমূহক ভিত্তি কৰি এই এপটোৱে আপোনাৰ অৱস্থান নিৰ্ণয় কৰিব পাৰে। এই অৱস্থানৰ সেৱাসমূহ অন হৈ থাকিলে আৰু আপোনাৰ টিভিত উপলব্ধ হ\'লেহে এপটোৱে সেইবোৰ ব্যৱহাৰ কৰিবলৈ সক্ষম হ\'ব।"</string>
+ <string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"এই এপটোৱে ম\'বাইলৰ টাৱাৰ আৰু ৱাই-ফাইৰ নেটৱৰ্ক আদিৰ দৰে নেটৱৰ্কৰ উৎসসমূহক ভিত্তি কৰি আপোনাৰ অৱস্থান চিনাক্ত কৰিব পাৰে। সেই অৱস্থান সেৱাসমূহ আপোনাৰ ফ\'নত সক্ষম অৱস্থাত থাকিলেহে এপটোৱে সেইবোৰ ব্যৱহাৰ কৰিব পাৰিব।"</string>
+ <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"আপোনাৰ অডিঅ\' ছেটিংসমূহ সলনি কৰক"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"এপটোক ভলিউমৰ দৰে গ্ল\'বেল অডিঅ\' ছেটিংসমূহ যাৰ স্পীকাৰক আউটপুটৰ বাবে ব্যৱহাৰ হয় তাক সলনি কৰিবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"অডিঅ\' ৰেকর্ড কৰক"</string>
+ <string name="permdesc_recordAudio" msgid="4245930455135321433">"এই এপটোৱে যিকোনো সময়তে মাইক্ৰ\'ফ\'ন ব্যৱহাৰ কৰি অডিঅ\' ৰেকৰ্ড কৰিব পাৰে।"</string>
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"ছিমলৈ নিৰ্দেশ পঠিয়াব পাৰে"</string>
+ <string name="permdesc_sim_communication" msgid="5725159654279639498">"ছিমলৈ নিৰ্দেশসমূহ প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে। ই অতি ক্ষতিকাৰক।"</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"ফট\' তোলা আৰু ভিডিঅ\' ৰেকৰ্ড কৰা"</string>
+ <string name="permdesc_camera" msgid="5392231870049240670">"এই এপে যিকোনো সময়তে কেমেৰা ব্যৱহাৰ কৰি ফট\' তুলিব আৰু ভিডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
+ <string name="permlab_vibrate" msgid="7696427026057705834">"কম্পন নিয়ন্ত্ৰণ কৰক"</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"ভাইব্ৰেটৰ নিয়ন্ত্ৰণ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_callPhone" msgid="3925836347681847954">"পোনপটীয়াকৈ ফ\'ন নম্বৰলৈ কল কৰক"</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"আপোনাৰ কোনো ব্যাঘাত নোহোৱাকৈ ফ\'ন নম্বৰবোৰত কল কৰিবলৈ এপক অনুমতি দিয়ে৷ ইয়াৰ ফলত অপ্ৰত্যাশিত মাচুল ভৰিবলগা বা কলবোৰ কৰা হ\'ব পাৰে৷ মনত ৰাখিব যে ই এপটোক জৰুৰীকালীন নম্বৰবোৰত কল কৰিবলৈ অনুমতি নিদিয়ে৷ ক্ষতিকাৰক এপসমূহে আপোনাৰ অনুমতি নোলোৱাকৈয়ে কল কৰি আপোনাক টকা খৰছ কৰাব পাৰে৷"</string>
+ <string name="permlab_accessImsCallService" msgid="3574943847181793918">"আইএমএছ কল সেৱা ব্যৱহাৰ কৰিব পাৰে"</string>
+ <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"আপোনাৰ হস্তক্ষেপৰ অবিহনে আইএমএছ সেৱা ব্যৱহাৰ কৰি কল কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_readPhoneState" msgid="9178228524507610486">"ফ\'নৰ স্থিতি আৰু পৰিচয় পঢ়ক"</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ডিভাইচত থকা ফ\'নৰ সুবিধাসমূহ ব্য়ৱহাৰ কৰিবলৈ এপটোক অনুমতি দিয়ে৷ এই অনুমতিয়ে কোনো কল সক্ৰিয় হৈ থাককেই বা নাথাকক আৰু দূৰবৰ্তী নম্বৰটো কলৰ দ্বাৰা সংযোজিত হওকেই বা নহওক এপটোক ফ\'ন নম্বৰ আৰু ডিভাইচৰ পৰিচয় নিৰ্ধাৰণ কৰিবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"ছিষ্টেমৰ জৰিয়তে কল কৰিব পাৰে"</string>
+ <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"কল কৰাৰ অভিজ্ঞতাক উন্নত কৰিবলৈ এপটোক ছিষ্টেমৰ জৰিয়তে কলসমূহ কৰিবলৈ দিয়ে।"</string>
+ <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
+ <skip />
+ <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
+ <skip />
+ <string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"ফ\'ন নম্বৰসমূহ পঢ়ে"</string>
+ <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"এপটোক ডিভাইচটোৰ ফ\'ন নম্বৰসমূহ চাবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"টে\'বলেট সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক"</string>
+ <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"টিভি সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ে"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ফ\'ন সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক"</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"টে\'বলেট সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"টিভিটোক সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ফ\'ন সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ইনফ্ৰাৰেড ট্ৰান্সমিট কৰিব পাৰে"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"টে\'বলেটৰ ইনফ্ৰাৰেড ট্ৰান্সমিটাৰ ব্যৱহাৰ কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"টিভিৰ ইনফ্ৰাৰেড ট্ৰান্সমিটাৰ ব্যৱহাৰ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"ফ\'নৰ ইনফ্ৰাৰেড ট্ৰান্সমিটাৰ ব্যৱহাৰ কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_setWallpaper" msgid="6627192333373465143">"ৱালপেপাৰ ছেট কৰক"</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"ছিষ্টেমৰ ৱালপেপাৰ ছেট কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"আপোনাৰ ৱালপেপাৰৰ আকাৰ মিলাওক"</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"ছিষ্টেমৰ ৱালপেপাৰৰ আকাৰ হিণ্ট ছেট কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_setTimeZone" msgid="2945079801013077340">"সময় মণ্ডল ছেট কৰক"</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"টে\'বলেটৰ সময় মণ্ডল সলনি কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"টিভিৰ সময় মণ্ডল সলনি কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"ফ\'নৰ সময় মণ্ডল সলনি কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_getAccounts" msgid="1086795467760122114">"ডিভাইচত একাউণ্টবোৰ বিচাৰক"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"এপটোক টেবলেটটোৰ জ্ঞাত একাউণ্টসমূহৰ সূচীখন পাবলৈ অনুমতি দিয়ে৷ এইটোৱে আপুনি ইনষ্টল কৰি ৰখা এপ্লিকেশ্বনসমূহে সৃষ্টি কৰা যিকোনো একাউণ্টক অন্তৰ্ভুক্ত কৰিব পাৰে৷"</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"এপটোক টিভিটোৱে জনা একাউণ্টসমূহৰ সূচীখন পাবলৈ অনুমতি দিয়ে। এইটোৱে আপুনি ইনষ্টল কৰি ৰখা এপ্লিকেশ্বনসমূহৰ দ্বাৰা সৃষ্ট যিকোনো একাউণ্টক অন্তৰ্ভুক্ত কৰিব পাৰে৷"</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"এপটোক ফ\'নটোৰ জ্ঞাত একাউণ্টসমূহৰ সূচীখন পাবলৈ অনুমতি দিয়ে৷ এইটোৱে আপুনি ইনষ্টল কৰি ৰখা এপ্লিকেশ্বনসমূহে সৃষ্টি কৰা যিকোনো একাউণ্টক অন্তৰ্ভুক্ত কৰিব পাৰে৷"</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"নেটৱৰ্কৰ সংযোগবোৰ চাওক"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"মজুত থকা আৰু সংযোগ হৈ থকা নেটৱৰ্ক সংযোগসমূহৰ বিষয়ে তথ্য চাবলৈ এপটোক অনুমতি দিয়ে৷"</string>
+ <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"সম্পূর্ণ নেটৱর্কৰ সুবিধা লাভ কৰিব পাৰে"</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"এপটোক নেটৱৰ্ক ছ\'কেটবোৰ সৃষ্টি কৰিবলৈ আৰু কাষ্টম নেটৱৰ্ক প্ৰ\'ট\'কল ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে৷ ব্ৰাউজাৰ আৰু অন্য এপ্লিকেশ্বনসমূহে ইণ্টাৰনেটলৈ ডেটা পঠিওৱা মাধ্য়ম প্ৰদান কৰে, গতিকে ইণ্টাৰনেটলৈ ডেটা পঠিয়াবলৈ এই অনুমতিৰ প্ৰয়োজন নাই৷"</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"নেটৱৰ্কৰ সংযোগ সলনি কৰক"</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"নেটৱৰ্ক সংযোগৰ অৱস্থাটো সলনি কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_changeTetherState" msgid="5952584964373017960">"টেডাৰিং সংযোগ সলনি কৰক"</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"টেডাৰ হৈ থকা ইণ্টাৰনেট সংযোগৰ অৱস্থা সলনি কৰিবলৈ এপটোক অনুমতি দিয়ে৷"</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"ৱাই-ফাইৰ সংযোগবোৰ চাওক"</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"ৱাই-ফাই সক্ষম কৰা হ\'ল নে নাই আৰু সংযোগ হৈ থকা ৱাই-ফাই ডিভাইচসমূহৰ নামবোৰৰ দৰে ৱাই-ফাইৰ ইণ্টাৰনেট সম্পর্কীয় তথ্য চাবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_changeWifiState" msgid="6550641188749128035">"ৱাই-ফাই সংযোগ কৰক আৰু ইয়াৰ সংযোগ বিচ্ছিন্ন কৰক"</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"এপটোক ৱাই-ফাই এক্সেছ পইণ্টলৈ সংযোগ কৰিবলৈ আৰু তাৰ সংযোগ বিচ্ছিন্ন কৰিবলৈ আৰু ৱাই-ফাই নেটৱৰ্কসমূহৰ বাবে ডিভাইচ কনফিগাৰেশ্বনত সাল-সলনি কৰিবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"ৱাই-ফাই মাল্টিকাষ্ট প্ৰচাৰৰ অনুমতি দিয়ক"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"আপোনাৰ টেবলেটৰ লগতে মাল্টিকাষ্ট ঠিকনাবোৰ ও ব্যৱহাৰ কৰি এপক ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট প্ৰাপ্ত কৰিবলৈ অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰিৰ অধিক চ্চাৰ্জ ব্যৱহাৰ কৰে।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"কেৱল আপোনাৰ টিভিটোৱেই নহয়, মাল্টিকাষ্ট ঠিকনা ব্যৱহাৰ কৰি এটা ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট লাভ কৰিবলৈ এপটোক অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ অধিক বেটাৰি ব্যৱহাৰ কৰে।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"আপোনাৰ ফ\'নৰ লগতে মাল্টিকাষ্ট ঠিকনাবোৰ ও ব্যৱহাৰ কৰি এপক ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট প্ৰাপ্ত কৰিবলৈ অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰিৰ অধিক চ্চাৰ্জ ব্যৱহাৰ কৰে।"</string>
+ <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"ব্লুটুথ ছেটিংসমূহ ব্যৱহাৰ কৰক"</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"স্থানীয় ব্লুটুথ টে\'বলেট কনফিগাৰ কৰিবলৈ আৰু দূৰৱৰ্তী ডিভাইচসমূহৰ সৈতে যোৰা লগাবলৈ আৰু বিচাৰি উলিয়াবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"স্থানীয় ব্লুটুথ টিভি কনফিগাৰ কৰিবলৈ আৰু দূৰৱৰ্তী ডিভাইচসমূহৰ সৈতে যোৰাবদ্ধ কৰিবলৈ আৰু বিচাৰি উলিয়াবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"স্থানীয় ব্লুটুথ ফ\'ন কনফিগাৰ কৰিবলৈ আৰু দূৰৱৰ্তী ডিভাইচসমূহৰ সৈতে যোৰা লগাবলৈ আৰু বিচাৰি উলিয়াবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAXৰ লগত সংযোগ কৰক আৰু ইয়াৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"WiMAX সক্ষম হৈ আছেনে নাই আৰু সংযোজিত যিকোনো WiMAX নেটৱৰ্কৰ বিষয়ে তথ্য নিৰ্ধাৰণ কৰিবলৈ এপটোক অনুমতি দিয়ে৷"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAXৰ স্থিতি সলনি কৰক"</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"এপটোক টেবলেটলৈ সংযোগ কৰিবলৈ আৰু WiMAX নেটৱৰ্কসমূহৰ পৰা টেবলেটৰ সংযোগ বিচ্ছিন্ন কৰিবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"এপটোক টিভিৰ লগত সংযোগ কৰিবলৈ আৰু WiMAX নেটৱৰ্কসমূহৰ পৰা টিভিৰ সংযোগ বিচ্ছিন্ন কৰিবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"এপটোক ফ\'নলৈ সংযোগ কৰিবলৈ আৰু WiMAX নেটৱৰ্কসমূহৰ পৰা ফ\'নৰ সংযোগ বিচ্ছিন্ন কৰিবলৈ অনুমতি দিয়ে৷"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"ব্লুটুথ ডিভাইচবোৰৰ সৈতে যোৰা লগাওক"</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"টেবলেটত ব্লুটুথৰ কনফিগাৰেশ্বন চাবলৈ আৰু যোৰা লগোৱা ডিভাইচসমূহৰ জৰিয়তে সংযোগ কৰিবলৈ আৰু সংযোগৰ অনুৰোধ স্বীকাৰ কৰিবলৈ এপটোক অনুমতি দিয়ে৷"</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"টিভিটোত ব্লুটুথৰ কনফিগাৰেশ্বন চাবলৈ আৰু যোৰ পাতি থোৱা ডিভাইচসমূহৰ সৈতে সংযোগ কৰিবলৈ আৰু গ্ৰহণ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ফ\'নটোত ব্লুটুথৰ কনফিগাৰেশ্বন চাবলৈ আৰু যোৰা লগোৱা ডিভাইচসমূহৰ জৰিয়তে সংযোগ কৰিবলৈ আৰু সংযোগৰ অনুৰোধ স্বীকাৰ কৰিবলৈ এপটোক অনুমতি দিয়ে৷"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"নিয়েৰ ফিল্ড কমিউনিকেশ্বন নিয়ন্ত্ৰণ কৰক"</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"এপটোক নিয়েৰ ফিল্ড কমিউনিকেশ্বন (NFC) টেগ, কাৰ্ড আৰু ৰিডাৰসমূহৰ সৈতে যোগাযোগ কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"আপোনাৰ স্ক্ৰীণ ল\'ক অক্ষম কৰক"</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"এপটোক কী ল\'ক আৰু জড়িত হোৱা যিকোনো পাছৱৰ্ডৰ সুৰক্ষা অক্ষম কৰিব দিয়ে৷ উদাহৰণ স্বৰূপে, কোনো অন্তৰ্গামী ফ\'ন কল উঠোৱাৰ সময়ত ফ\'নটোৱে কী-লকটো অক্ষম কৰে, তাৰপিছত কল শেষ হ\'লেই কী লকটো পুনৰ সক্ষম কৰে৷"</string>
+ <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
+ <skip />
+ <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
+ <skip />
+ <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
+ <skip />
+ <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_partial (735082772341716043) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_insufficient (4596546021310923214) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_imager_dirty (1087209702421076105) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_fast (6470642383109155969) -->
+ <skip />
+ <!-- no translation found for fingerprint_acquired_too_slow (59250885689661653) -->
+ <skip />
+ <string-array name="fingerprint_acquired_vendor">
+ </string-array>
+ <!-- no translation found for fingerprint_not_recognized (2690661881608146617) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_hw_not_available (7955921658939936596) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_no_space (1055819001126053318) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_timeout (3927186043737732875) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_canceled (4402024612660774395) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_lockout (5536934748136933450) -->
+ <skip />
+ <string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"অত্যধিক প্ৰয়াস। ফিংগাৰপ্ৰিণ্ট ছেন্সৰ অক্ষম কৰা হ\'ল।"</string>
+ <!-- no translation found for fingerprint_error_unable_to_process (6107816084103552441) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_no_fingerprints (7654382120628334248) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_hw_not_present (5729436878065119329) -->
+ <skip />
+ <!-- no translation found for fingerprint_name_template (5870957565512716938) -->
+ <skip />
+ <string-array name="fingerprint_error_vendor">
+ </string-array>
+ <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ছিংকৰ ছেটিংসমূহ পঢ়ক"</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ কোনো একাউণ্টত ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ছিংকক অন আৰু অফ ট\'গল কৰক"</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"এপটোক কোনো একাউণ্টৰ ছিংক সম্পৰ্কীয় ছেটিংসমূহ সংশোধন কৰিবলৈ অনুমতি দিয়ে৷ উদাহৰণ স্বৰূপে, এই কাৰ্যক কোনো একাউণ্টৰ জৰিয়তে People এপটোৰ ছিংক সক্ষম কৰিবলৈ ব্যৱহাৰ কৰিব পাৰি৷"</string>
+ <string name="permlab_readSyncStats" msgid="7396577451360202448">"ছিংকৰ পৰিসংখ্যা পঢ়ক"</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"ছিংকৰ কাৰ্যক্ৰমসমূহৰ ইতিহাস আৰু ছিংক কৰা ডেটাৰ পৰিমাণসহ কোনো একাউণ্টৰ ছিংকৰ তথ্য পঢ়িবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"আপোনাৰ ইউএছবি সঞ্চয়াগাৰৰ সমলবোৰ পঢ়ক"</string>
+ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"আপোনাৰ এছডি কাৰ্ডৰ সমলবোৰ পঢ়ক"</string>
+ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"আপোনাৰ ইউএছবি সঞ্চয়াগাৰৰ সমলসমূহ পঢ়িবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"আপোনাৰ এছডি কাৰ্ডৰ সমল পঢ়িবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"আপোনাৰ ইউএছবি সঞ্চয়াগাৰৰ সমলবোৰ সংশোধন কৰক বা মচক"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"আপোনাৰ এছডি কাৰ্ডৰ সমলবোৰ সংশোধন কৰক বা মচক"</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"এপটোক ইউএছবি সঞ্চয়াগাৰত লিখাৰ অনুমতি দিয়ে।"</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"এপটোক এছডি কাৰ্ডত লিখাৰ অনুমতি দিয়ে।"</string>
+ <string name="permlab_use_sip" msgid="2052499390128979920">"SIP কল কৰা/পোৱা"</string>
+ <string name="permdesc_use_sip" msgid="2297804849860225257">"এপটোক SIP কলসমূহ কৰিবলৈ আৰু পাবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"নতুন টেলিকম ছিম সংযোগসমূহ পঞ্জীয়ন কৰা"</string>
+ <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"এপটোক নতুন টেলিকম সংযোগ পঞ্জীয়ন কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_register_call_provider" msgid="108102120289029841">"নতুন টেলিকম সংযোগসমূহ পঞ্জীয়ন কৰা"</string>
+ <string name="permdesc_register_call_provider" msgid="7034310263521081388">"এপটোক নতুন টেলিকম সংযোগ পঞ্জীয়ন কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_connection_manager" msgid="1116193254522105375">"টেলিকম সংযোগ পৰিচালনা কৰা"</string>
+ <string name="permdesc_connection_manager" msgid="5925480810356483565">"এপটোক টেলিকম সংযোগ পৰিচালনা কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_bind_incall_service" msgid="6773648341975287125">"ইন-কল স্ক্ৰীণৰ সৈতে সংযোগ স্থাপন"</string>
+ <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"ব্যৱহাৰকাৰীয়ে কেতিয়া আৰু কেনেদৰে ইন-কল-স্ক্ৰীণ চাব, তাক নিয়ন্ত্ৰণ কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
+ <string name="permlab_bind_connection_service" msgid="3557341439297014940">"টেলিফ\'নী সেৱাসমূহৰ সৈতে সংযোগ স্থাপন"</string>
+ <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"কল কৰিবলৈ/লাভ কৰিবলৈ টেলিফ\'নী সেৱাসমূহৰ সৈতে এপক সংযোগ স্থাপনৰ বাবে অনুমতি দিয়ে।"</string>
+ <string name="permlab_control_incall_experience" msgid="9061024437607777619">"ইন-কল ব্যৱহাৰকাৰীৰ অভিজ্ঞতা প্ৰদান কৰা"</string>
+ <string name="permdesc_control_incall_experience" msgid="915159066039828124">"এপটোক ইন-কল ব্যৱহাৰকাৰীৰ অভিজ্ঞতা প্ৰদান কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"নেটৱর্কৰ পূৰ্বতে হোৱা ব্যৱহাৰৰ বিষয়ে পঢ়ক"</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"এপটোক বিশেষ নেটৱৰ্কবিলাকৰ আৰু এপ্সমূহৰ নেটৱৰ্ক ব্যৱহাৰৰ ইতিহাস পঢ়িবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"নেটৱর্কৰ নীতি পৰিচালনা কৰক"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"এপটোক নেটৱৰ্ক সংযোগৰ নীতিসমূহ পৰিচালনা কৰিবলৈ আৰু এপ্-বিশেষ নিয়ম সংজ্ঞাবদ্ধ কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"নেটৱর্ক ব্যৱহাৰৰ হিচাপ সলনি কৰক"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"এপ অনুসুৰি নেটৱর্কৰ ব্যৱহাৰৰ হিচাপ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। এয়া সাধাৰণ এপবোৰৰ ব্যৱহাৰৰ বাবে নহয়।"</string>
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"প্ৰৱেশ জাননীসমূহ"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"অন্য এপসমূহৰদ্বাৰা প\'ষ্ট কৰা জাননীসমূহকে ধৰি জাননী বিচাৰি উলিয়াবলৈ, পৰীক্ষা কৰিবলৈ আৰু মচিবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"এটা জাননী শুনা সেৱাৰ লগত সংযুক্ত হ\'ব পাৰে"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"এটা জাননী শ্ৰৱণ সেৱা প্ৰদানকাৰীৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফেইচৰ লগত সংযুক্ত হ\'বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"এটা অৱস্থা প্ৰদানকাৰী সেৱাৰ লগত সংযুক্ত হ\'ব পাৰে"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"অৱস্থা প্ৰদানকাৰী সেৱাৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফেচইলৈ সংযুক্ত হ\'বলৈ বাহকক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"এটা ড্ৰিম সেৱাৰ লগত সংযুক্ত হ\'ব পাৰে"</string>
+ <string name="permdesc_bindDreamService" msgid="7325825272223347863">"এটা ড্ৰিম সেৱাৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফেইচলৈ সংযুক্ত হ\'বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"বাহকৰদ্বাৰা প্ৰদান কৰা কনফিগাৰেশ্বন এপক কামত লগাব পাৰে"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"বাহকে যোগান ধৰা কনফিগাৰেশ্বন এপ্ ব্যৱহাৰ কৰিবলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"নেটৱৰ্ক অৱস্থাসমূহৰ ওপৰত নিৰীক্ষণৰ বাবে শুনিব পাৰে"</string>
+ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"এটা এপ্লিকেশ্বনক নেটৱৰ্ক অৱস্থাসমূহত নিৰীক্ষণৰ বাবে শুনিবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ইনপুট ডিভাইচ কেলিব্ৰেশ্বন সলনি কৰিব পাৰে"</string>
+ <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"টাচ্চ স্ক্ৰীণৰ কেলিব্ৰেশ্বন পেৰামিটাৰ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM প্ৰমাণপত্ৰসমূহলৈ প্ৰৱেশ"</string>
+ <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"এটা এপ্লিকেশ্বনক DRM প্ৰমাণপত্ৰ গোটাবলৈ আৰু ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_handoverStatus" msgid="7820353257219300883">"Android বীম স্থানান্তৰণৰ স্থিতি লাভ কৰিব পাৰে"</string>
+ <string name="permdesc_handoverStatus" msgid="4788144087245714948">"বৰ্তমানৰ Android Beam স্থানান্তৰণসমূহৰ বিষয়ে তথ্য পাবলৈ এই এপ্লিকেশ্বনক অনুমতি দিয়ে"</string>
+ <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"DRM প্ৰমাণপত্ৰসমূহ আঁতৰোৱা"</string>
+ <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"এটা এপ্লিকেশ্বনক DRM প্ৰমাণপত্ৰ আঁতৰাবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে কেতিয়াও প্ৰয়োজন নহয়।"</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"বাহকৰ মেছেজিং সেৱাৰ লগত সংযোগ কৰে"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"বাহক মেছেজিং সেৱাৰ উচ্চ স্তৰৰ ইণ্টাৰফেইচত সংযোগ কৰিবলৈ ধাৰকক অনুমতি দিয়ে। এয়া সাধাৰণ এপবোৰৰ বাবে কেতিয়াও প্ৰয়োজন নহয়।"</string>
+ <!-- no translation found for permlab_bindCarrierServices (3233108656245526783) -->
+ <skip />
+ <!-- no translation found for permdesc_bindCarrierServices (1391552602551084192) -->
+ <skip />
+ <!-- no translation found for permlab_access_notification_policy (4247510821662059671) -->
+ <skip />
+ <!-- no translation found for permdesc_access_notification_policy (3296832375218749580) -->
+ <skip />
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"পাছৱর্ডৰ নিয়ম ছেট কৰক"</string>
+ <!-- no translation found for policydesc_limitPassword (2502021457917874968) -->
+ <skip />
+ <string name="policylab_watchLogin" msgid="5091404125971980158">"স্ক্ৰীণ আনলক কৰা প্ৰয়াসবোৰ পৰ্যবেক্ষণ কৰিব পাৰে"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে টে\'বলেটটো লক কৰক বা টে\'বলেটটোৰ সকলো ডেটা মোহাৰক।"</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে টিভিটো লক কৰক বা টিভিটোৰ সকলো ডেটা মোহাৰক।"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"স্ক্ৰীণ আনলক কৰোতে লিখা অশুদ্ধ পাছৱৰ্ডৰ হিচাপ ৰাখক, আৰু যদিহে অত্যধিকবাৰ অশুদ্ধ পাছৱৰ্ড লিখা হয় তেন্তে ফ\'নটো লক কৰক বা ফ\'নটোৰ সকলো ডেটা মোহাৰক।"</string>
+ <!-- no translation found for policydesc_watchLogin_secondaryUser (4280246270601044505) -->
+ <skip />
+ <!-- no translation found for policydesc_watchLogin_secondaryUser (3484832653564483250) -->
+ <skip />
+ <!-- no translation found for policydesc_watchLogin_secondaryUser (2185480427217127147) -->
+ <skip />
+ <!-- no translation found for policylab_resetPassword (4934707632423915395) -->
+ <skip />
+ <!-- no translation found for policydesc_resetPassword (1278323891710619128) -->
+ <skip />
+ <string name="policylab_forceLock" msgid="2274085384704248431">"স্ক্ৰীণখন লক কৰক"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"স্ক্ৰীণ কেনেকৈ আৰু কেতিয়া ল\'ক হ\'ব লাগে সেয়া নিয়ন্ত্ৰণ কৰক।"</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"সকলো ডেটা মচক"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"সতৰ্কবাণী প্ৰেৰণ নকৰাকৈয়ে ফেক্টৰী ডেটা ৰিছেট কৰি টেবলেটৰ ডেটা মচক।"</string>
+ <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"সতৰ্কবাণী প্ৰেৰণ নকৰাকৈয়ে ফেক্টৰী ডেটা ৰিছেট কৰি টিভিৰ ডেটা মোহাৰক।"</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"সতৰ্কবাণী প্ৰেৰণ নকৰাকৈয়ে ফেক্টৰী ডেটা ৰিছেট কৰি ফ\'নৰ ডেটা মচক।"</string>
+ <!-- no translation found for policylab_wipeData_secondaryUser (8362863289455531813) -->
+ <skip />
+ <!-- no translation found for policydesc_wipeData_secondaryUser (6336255514635308054) -->
+ <skip />
+ <!-- no translation found for policydesc_wipeData_secondaryUser (2086473496848351810) -->
+ <skip />
+ <!-- no translation found for policydesc_wipeData_secondaryUser (6787904546711590238) -->
+ <skip />
+ <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ডিভাইচৰ বাবে গ্ল\'বেল প্ৰক্সী ছেট কৰক"</string>
+ <!-- no translation found for policydesc_setGlobalProxy (8459859731153370499) -->
+ <skip />
+ <!-- no translation found for policylab_expirePassword (5610055012328825874) -->
+ <skip />
+ <!-- no translation found for policydesc_expirePassword (5367525762204416046) -->
+ <skip />
+ <string name="policylab_encryptedStorage" msgid="8901326199909132915">"সঞ্চয়াগাৰৰ এনক্ৰিপশ্বন ছেট কৰক"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"সঞ্চয় কৰি ৰখা ডেটাক এনক্ৰিপ্ট কৰাৰ প্ৰয়োজন।"</string>
+ <string name="policylab_disableCamera" msgid="6395301023152297826">"কেমেৰাবোৰ অক্ষম কৰক"</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"সকলো ডিভাইচৰ কেমেৰাবোৰ ব্যৱহাৰ কৰাত বাধা দিয়ক।"</string>
+ <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"স্ক্ৰীণ লকৰ কিছুমান সুবিধা অক্ষম কৰক"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"স্ক্ৰীণ লকৰ কিছুমান সুবিধা ব্যৱহাৰ হোৱাত বাধা দিয়ক।"</string>
+ <string-array name="phoneTypes">
+ <item msgid="8901098336658710359">"ঘৰ"</item>
+ <item msgid="869923650527136615">"ম\'বাইল"</item>
+ <item msgid="7897544654242874543">"কৰ্মস্থান"</item>
+ <item msgid="1103601433382158155">"কর্মস্থানৰ ফেক্সৰ নম্বৰ"</item>
+ <item msgid="1735177144948329370">"ঘৰৰ ফেক্স নম্বৰ"</item>
+ <item msgid="603878674477207394">"পেজাৰ"</item>
+ <item msgid="1650824275177931637">"অন্যান্য"</item>
+ <item msgid="9192514806975898961">"নিজৰ উপযোগিতা অনুযায়ী"</item>
+ </string-array>
+ <string-array name="emailAddressTypes">
+ <item msgid="8073994352956129127">"ঘৰ"</item>
+ <item msgid="7084237356602625604">"কৰ্মস্থান"</item>
+ <item msgid="1112044410659011023">"অন্যান্য"</item>
+ <item msgid="2374913952870110618">"নিজৰ উপযোগিতা অনুযায়ী"</item>
+ </string-array>
+ <string-array name="postalAddressTypes">
+ <item msgid="6880257626740047286">"ঘৰ"</item>
+ <item msgid="5629153956045109251">"কৰ্মস্থান"</item>
+ <item msgid="4966604264500343469">"অন্যান্য"</item>
+ <item msgid="4932682847595299369">"নিজৰ উপযোগিতা অনুযায়ী"</item>
+ </string-array>
+ <string-array name="imAddressTypes">
+ <item msgid="1738585194601476694">"ঘৰ"</item>
+ <item msgid="1359644565647383708">"কৰ্মস্থান"</item>
+ <item msgid="7868549401053615677">"অন্যান্য"</item>
+ <item msgid="3145118944639869809">"নিজৰ উপযোগিতা অনুযায়ী"</item>
+ </string-array>
+ <string-array name="organizationTypes">
+ <item msgid="7546335612189115615">"কৰ্মস্থান"</item>
+ <item msgid="4378074129049520373">"অন্যান্য"</item>
+ <item msgid="3455047468583965104">"নিজৰ উপযোগিতা অনুযায়ী"</item>
+ </string-array>
+ <string-array name="imProtocols">
+ <item msgid="8595261363518459565">"এআইএম"</item>
+ <item msgid="7390473628275490700">"Windows Live"</item>
+ <item msgid="7882877134931458217">"Yahoo"</item>
+ <item msgid="5035376313200585242">"Skype"</item>
+ <item msgid="7532363178459444943">"QQ"</item>
+ <item msgid="3713441034299660749">"Google Talk"</item>
+ <item msgid="2506857312718630823">"ICQ"</item>
+ <item msgid="1648797903785279353">"Jabber"</item>
+ </string-array>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"ঘৰৰ ফ\'ন নম্বৰ"</string>
+ <string name="phoneTypeMobile" msgid="6501463557754751037">"ম\'বাইল"</string>
+ <string name="phoneTypeWork" msgid="8863939667059911633">"কৰ্মস্থানৰ ফ\'ন নম্বৰ"</string>
+ <string name="phoneTypeFaxWork" msgid="3517792160008890912">"কর্মস্থানৰ ফেক্সৰ নম্বৰ"</string>
+ <string name="phoneTypeFaxHome" msgid="2067265972322971467">"ঘৰৰ ফেক্স নম্বৰ"</string>
+ <string name="phoneTypePager" msgid="7582359955394921732">"পেজাৰৰ নম্বৰ"</string>
+ <string name="phoneTypeOther" msgid="1544425847868765990">"অন্যান্য"</string>
+ <string name="phoneTypeCallback" msgid="2712175203065678206">"কলবেক কৰক"</string>
+ <string name="phoneTypeCar" msgid="8738360689616716982">"গাড়ী"</string>
+ <string name="phoneTypeCompanyMain" msgid="540434356461478916">"কোম্পানীৰ মুখ্য ফ\'ন নম্বৰ"</string>
+ <string name="phoneTypeIsdn" msgid="8022453193171370337">"আইএছডিএন"</string>
+ <string name="phoneTypeMain" msgid="6766137010628326916">"মুখ্য ফ\'ন নম্বৰ"</string>
+ <string name="phoneTypeOtherFax" msgid="8587657145072446565">"অন্য ফেক্স নম্বৰ"</string>
+ <string name="phoneTypeRadio" msgid="4093738079908667513">"ৰেডিঅ’ ফ\'ন নম্বৰ"</string>
+ <string name="phoneTypeTelex" msgid="3367879952476250512">"টেলেক্স ফ\'ন নম্বৰ"</string>
+ <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
+ <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"কৰ্মস্থানৰ ম\'বাইল নম্বৰ"</string>
+ <string name="phoneTypeWorkPager" msgid="649938731231157056">"কৰ্মস্থানৰ পেজাৰৰ নম্বৰ"</string>
+ <string name="phoneTypeAssistant" msgid="5596772636128562884">"সহায়ক"</string>
+ <string name="phoneTypeMms" msgid="7254492275502768992">"এমএমএছ"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="eventTypeBirthday" msgid="2813379844211390740">"জন্মদিন"</string>
+ <string name="eventTypeAnniversary" msgid="3876779744518284000">"বর্ষপূর্তি"</string>
+ <string name="eventTypeOther" msgid="7388178939010143077">"অন্যান্য"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"ঘৰ"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"কৰ্মস্থান"</string>
+ <string name="emailTypeOther" msgid="2923008695272639549">"অন্যান্য"</string>
+ <string name="emailTypeMobile" msgid="119919005321166205">"ম\'বাইল"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"ঘৰৰ ঠিকনা"</string>
+ <string name="postalTypeWork" msgid="5268172772387694495">"কৰ্মস্থানৰ ঠিকনা"</string>
+ <string name="postalTypeOther" msgid="2726111966623584341">"অন্যান্য"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"ঘৰ"</string>
+ <string name="imTypeWork" msgid="1371489290242433090">"কৰ্মস্থান"</string>
+ <string name="imTypeOther" msgid="5377007495735915478">"অন্যান্য"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="imProtocolAim" msgid="7050360612368383417">"এআইএম"</string>
+ <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
+ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
+ <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
+ <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
+ <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
+ <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
+ <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
+ <string name="orgTypeWork" msgid="29268870505363872">"কৰ্মস্থান"</string>
+ <string name="orgTypeOther" msgid="3951781131570124082">"অন্যান্য"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="relationTypeAssistant" msgid="6274334825195379076">"সহায়ক"</string>
+ <string name="relationTypeBrother" msgid="8757913506784067713">"ভাতৃ"</string>
+ <string name="relationTypeChild" msgid="1890746277276881626">"শিশু"</string>
+ <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"সংগী"</string>
+ <string name="relationTypeFather" msgid="5228034687082050725">"দেউতা"</string>
+ <string name="relationTypeFriend" msgid="7313106762483391262">"বন্ধু"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"মেনেজাৰ"</string>
+ <string name="relationTypeMother" msgid="4578571352962758304">"মাতৃ"</string>
+ <string name="relationTypeParent" msgid="4755635567562925226">"অভিভাৱক"</string>
+ <string name="relationTypePartner" msgid="7266490285120262781">"সংগী"</string>
+ <string name="relationTypeReferredBy" msgid="101573059844135524">"মাধ্যমেৰে"</string>
+ <string name="relationTypeRelative" msgid="1799819930085610271">"সম্বন্ধীয়"</string>
+ <string name="relationTypeSister" msgid="1735983554479076481">"ভনী"</string>
+ <string name="relationTypeSpouse" msgid="394136939428698117">"পতি-পত্নী"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"নিজৰ উপযোগিতা অনুযায়ী"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"ঘৰৰ ঠিকনা"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"কৰ্মস্থান"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"অন্যান্য"</string>
+ <string name="quick_contacts_not_available" msgid="746098007828579688">"এই সম্পৰ্ক চাবলৈ কোনো এপ্লিকেশ্বন পোৱা ন\'গল।"</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"পিন ক\'ড লিখক"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK আৰু নতুন পিন ক\'ড লিখক"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK ক\'ড"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"নতুন পিন ক\'ড"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17"></font>" পাছৱর্ড লিখিবলৈ টিপক"</string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"আনলক কৰিবলৈ পাছৱৰ্ড লিখক"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"আনলক কৰিবলৈ পিন লিখক"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ভুল পিন ক\'ড।"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"আনলক কৰিবলৈ মেনু টিপাৰ পিছত ০ টিপক।"</string>
+ <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"জৰুৰীকালীন নম্বৰ"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"কোনো সেৱা নাই"</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"স্ক্ৰীণ লক কৰা হ\'ল।"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"আনলক কৰিবলৈ বা জৰুৰীকালীন কল কৰিবলৈ মেনু টিপক।"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"আনলক কৰিবলৈ মেনু টিপক।"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"আনলক কৰিবলৈ আর্হি আঁকক"</string>
+ <!-- no translation found for lockscreen_emergency_call (5298642613417801888) -->
+ <skip />
+ <string name="lockscreen_return_to_call" msgid="5244259785500040021">"কললৈ উভতি যাওক"</string>
+ <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"শুদ্ধ!"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"আকৌ চেষ্টা কৰক"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"আকৌ চেষ্টা কৰক"</string>
+ <string name="lockscreen_storage_locked" msgid="9167551160010625200">"সকলো সুবিধা আৰু ডেটাৰ বাবে আনলক কৰক"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"গৰাকীৰ মুখাৱয়বৰ দ্বাৰা আনলক কৰা সর্বধিক সীমা অতিক্ৰম কৰা হ\'ল"</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"কোনো ছিম কাৰ্ড নাই"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"টে\'বলেটত ছিম কার্ড নাই।"</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"টিভিত ছিম কার্ড নাই।"</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ফ\'নত ছিম কার্ড নাই।"</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"এখন ছিম কাৰ্ড ভৰাওক।"</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"ছিম কাৰ্ডখন নাই বা পঢ়িব পৰা নগ\'ল। এখন ছিম কাৰ্ড ভৰাওক।"</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড।"</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"আপোনাৰ ছিম কাৰ্ডখন স্থায়ীভাৱে অক্ষম হৈছে।\n অন্য এখন ছিমৰ বাবে আপোনাৰ ৱায়াৰলেছ সেৱা প্ৰদানকাৰীৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"পূৰ্বৱৰ্তী ট্ৰেক"</string>
+ <string name="lockscreen_transport_next_description" msgid="573285210424377338">"পৰৱৰ্তী ট্ৰেক"</string>
+ <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"পজ কৰক"</string>
+ <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"প্লে কৰক"</string>
+ <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"বন্ধ কৰক"</string>
+ <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"ৰিৱাইণ্ড কৰক"</string>
+ <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"ফাষ্ট ফৰৱাৰ্ড"</string>
+ <string name="emergency_calls_only" msgid="6733978304386365407">"জৰুৰীকালীন কল মাত্ৰ"</string>
+ <string name="lockscreen_network_locked_message" msgid="143389224986028501">"নেটৱর্ক অৱৰোধিত"</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUKৰ দ্বাৰা লক কৰা ছিম কার্ড।"</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"ব্যৱহাৰকাৰীৰ নিৰ্দেশনা চাওক বা গ্ৰাহক সেৱা কেন্দ্ৰৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"ছিম কাৰ্ড লক কৰা হৈছে।"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"ছিম কার্ড আনলক কৰি থকা হৈছে…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"আপুনি অশুদ্ধভাৱে আপোনাৰ আনলক আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ আঁকিছে। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক।"</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"আপুনি অশুদ্ধভাৱে আপোনাৰ পাছৱৰ্ড <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক।"</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"আপুনি অশুদ্ধভাৱে আপোনাৰ পিন <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক।"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"আপুনি অশুদ্ধভাৱে আপোনাৰ লক খোলাৰ আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ আঁকিলে৷ <xliff:g id="NUMBER_1">%2$d</xliff:g> তকৈ অধিকবাৰ অসফলভাৱে কৰা প্ৰয়াসৰ পিছত, আপোনাৰ ফ\'নটো আনলক কৰিবৰ বাবে Google ছাইন ইনৰ জৰিয়তে কাৰ্যটো কৰিবলৈ কোৱা হ\'ব৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক৷"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"আপুনি অশুদ্ধভাৱে আপোনাৰ আনলক আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ দিলে। <xliff:g id="NUMBER_1">%2$d</xliff:g>টা অসফল প্ৰয়াসৰ পিছত আপোনাক আপোনাৰ টিভিটো আনলক কৰিবৰ বাবে Google ছাইন ইন ব্যৱহাৰ কৰিবলৈ কোৱা হ\'ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক।"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"আপুনি অশুদ্ধভাৱে আপোনাৰ লক খোলাৰ আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ আঁকিলে৷ <xliff:g id="NUMBER_1">%2$d</xliff:g> তকৈ অধিকবাৰ অসফলভাৱে কৰা প্ৰয়াসৰ পিছত, আপোনাৰ ফ\'নটো আনলক কৰিবৰ বাবে Google ছাইন ইনৰ জৰিয়তে কাৰ্যটো কৰিবলৈ কোৱা হ\'ব৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক৷"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"আপুনি টে\'বলেটটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আনলক কৰিবলৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰতকৈ বেছি প্ৰয়াস কৰিলে টে\'বলেটটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"আপুনি টিভিটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টিভিটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু আপুনি সকলো ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"আপুনি ফ\'নটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আনলক কৰিবলৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰতকৈ বেছি প্ৰয়াস কৰিলে ফ\'নটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"আপুনি অশুদ্ধভাৱে টে\'বলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ চেষ্টা কৰিছিল। টে\'বলেটটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"আপুনি টিভিটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। টিভিটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"আপুনি অশুদ্ধভাৱে ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ চেষ্টা কৰিছিল। ফ\'নটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> ছেকেণ্ডৰ পাছত চেষ্টা কৰক।"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"আর্হি পাহৰিলে নেকি?"</string>
+ <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"একাউণ্ট আনলক"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"বহুতবাৰ ভুলকৈ আর্হি অঁকা হ\'ল"</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"আনলক কৰিবলৈ নিজৰ Google একাউণ্টৰ জৰিয়তে ছাইন ইন কৰক।"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ব্যৱহাৰকাৰীৰ নাম (ইমেইল)"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"পাছৱৰ্ড"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ছাইন ইন কৰক"</string>
+ <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ব্যৱহাৰকাৰীৰ নাম আৰু পাছৱর্ড মান্য নহয়।"</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"আপোনাৰ ব্যৱহাৰকাৰী নাম আৰু পাছৱর্ড পাহৰিলে নেকি?\n"<b>"google.com/accounts/recovery"</b>" চাওক।"</string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"পৰীক্ষা কৰি থকা হৈছে…"</string>
+ <string name="lockscreen_unlock_label" msgid="737440483220667054">"আনলক"</string>
+ <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ধ্বনি অন হৈ আছে"</string>
+ <string name="lockscreen_sound_off_label" msgid="996822825154319026">"ধ্বনি অফ হৈ আছে"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"আর্হি অঁকা কার্য আৰম্ভ হ\'ল"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"আর্হি মচি পেলোৱা হ\'ল"</string>
+ <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"আৰ্হিত এটা বিন্দু যোগ কৰিছে"</string>
+ <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"চেল <xliff:g id="CELL_INDEX">%1$s</xliff:g> যোগ কৰা হ\'ল"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"আর্হি অঁকা সর্ম্পূণ হ\'ল"</string>
+ <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"আর্হিৰ ক্ষেত্ৰ।"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ৱিজেট %3$d-ৰ %2$d।"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ৱিজেট যোগ কৰক।"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"খালী"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"আনলক ক্ষেত্ৰ বিস্তাৰিত হৈছে।"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"আনলক ক্ষেত্ৰ সংকুচিত হৈছে।"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ৱিজেট।"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ব্যৱহাৰকাৰী নিৰ্বাচক"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"স্থিতি"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"কেমেৰা"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"মিডিয়াৰ নিয়ন্ত্ৰণসমূহ"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ৱিজেটৰ পুনঃক্ৰম আৰম্ভ হ\'ল।"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ৱিজেটৰ পুনঃক্ৰম সমাপ্ত হ\'ল।"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ৱিজেট <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> মচা হ\'ল।"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"আনলক ক্ষেত্ৰ বিস্তাৰ কৰক।"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"শ্লাইডৰদ্বাৰা আনলক।"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"আৰ্হিৰদ্বাৰা আনলক।"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"গৰাকীৰ মুখাৱয়বৰদ্বাৰা আনলক।"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"পিনৰদ্বাৰা আনলক।"</string>
+ <!-- no translation found for keyguard_accessibility_sim_pin_unlock (9149698847116962307) -->
+ <skip />
+ <!-- no translation found for keyguard_accessibility_sim_puk_unlock (9106899279724723341) -->
+ <skip />
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"পাছৱৰ্ডৰদ্বাৰা আনলক।"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"আৰ্হি ক্ষেত্ৰ।"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"শ্লাইড ক্ষেত্ৰ।"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?১২৩"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="granularity_label_character" msgid="7336470535385009523">"বর্ণ"</string>
+ <string name="granularity_label_word" msgid="7075570328374918660">"শব্দ"</string>
+ <string name="granularity_label_link" msgid="5815508880782488267">"লিংক"</string>
+ <string name="granularity_label_line" msgid="5764267235026120888">"লাইন"</string>
+ <string name="factorytest_failed" msgid="5410270329114212041">"ফেক্টৰীৰ পৰীক্ষা কৰিব পৰা নগ\'ল"</string>
+ <string name="factorytest_not_system" msgid="4435201656767276723">"কেৱল /ছিষ্টেম/এপ-ত ইনষ্টল কৰি থোৱা পেকেজৰ বাবেহে FACTORY_TEST কৰিব পৰা যায়।"</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST কার্যৰ বাবে কোনো পেকেজ পোৱা নগ\'ল।"</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"ৰিবুট কৰক"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"\"<xliff:g id="TITLE">%s</xliff:g>\"ত পৃষ্ঠাৰ প্ৰত্য়ুত্তৰ:"</string>
+ <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
+ <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"নেভিগেশ্বন নিশ্চিত কৰক"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"এই পৃষ্ঠাটোৰ পৰা আঁতৰি যাওক"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"এই পৃষ্ঠাটোতে থাকক"</string>
+ <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nআপুনি এই পৃষ্ঠাটো এৰি বেলেগলৈ যাব বিচাৰে নেকি?"</string>
+ <string name="save_password_label" msgid="6860261758665825069">"নিশ্চিত কৰক"</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"পৰামৰ্শ: জুম ইন আৰু আউট কৰিবলৈ দুবাৰ টিপক৷"</string>
+ <string name="autofill_this_form" msgid="4616758841157816676">"স্বয়ংপূৰ্তি"</string>
+ <string name="setup_autofill" msgid="7103495070180590814">"স্বয়ংপূৰ্তি ছেট আপ কৰক"</string>
+ <!-- no translation found for autofill_window_title (921006636895825007) -->
+ <skip />
+ <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
+ <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
+ <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"প্ৰদেশ"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"পিন ক\'ড"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"ৰাজ্য"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"পিন ক\'ড"</string>
+ <string name="autofill_county" msgid="237073771020362891">"জিলা"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"দ্বীপ"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"জিলা"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"বিভাগ"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"জিলাৰ মুৰব্বী"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"গাঁও"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"ক্ষেত্ৰ"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"এমিৰেট"</string>
+ <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"আপোনাৰ ৱেব বুকমার্কবোৰ আৰু ইতিহাস পঢ়ক"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰে ব্যৱহাৰ কৰা সকলো URLৰ ইতিহাস পঢ়িবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিং কৰিব পৰা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"আপোনাৰ ৱেব বুকমার্কবোৰ আৰু ইতিহাস লিখক"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"আপোনাৰ টেবলেটত সঞ্চয় কৰি ৰখা ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰৰ ইতিহাস সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিং কৰিব পৰা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"আপোনাৰ টিভিত সঞ্চয় কৰি ৰখা ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰৰ ইতিহাস সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিংৰ ক্ষমতা থকা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"আপোনাৰ ফ\'নত সঞ্চয় কৰি ৰখা ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰৰ ইতিহাস সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিং কৰিব পৰা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
+ <string name="permlab_setAlarm" msgid="1379294556362091814">"এলাৰ্ম ছেট কৰক"</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"এপটোক ইনষ্টল হৈ থকা এলাৰ্ম ক্লক এপত এলাৰ্ম ছেট কৰিবলৈ অনুমতি দিয়ে। কিছুমান এলাৰ্ম ক্লক এপত এই সুবিধাটো প্ৰযোজ্য নহ\'ব পাৰে।"</string>
+ <string name="permlab_addVoicemail" msgid="5525660026090959044">"ভইচমেইল যোগ কৰক"</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"আপোনাৰ ভইচমেইল ইনবক্সত বাৰ্তাবোৰ যোগ কৰিবলৈ এপটোক অনুমতি দিয়ক।"</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ব্ৰাউজাৰৰ জিঅ\'লোকেশ্বনৰ অনুমতিসমূহ সংশোধন কৰক"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ব্ৰাউজাৰৰ জিঅ\'লোকেশ্বন বিষয়ক অনুমতিসমূহ সংশোধন কৰিবলৈ এপটোক অনুমতি দিয়ে৷ ক্ষতিকাৰক এপবোৰে একপক্ষীয় ৱেবছাইটসমূহলৈ অৱস্থান সেৱাৰ তথ্য পঠিয়াবলৈ ইয়াক ব্যৱহাৰ কৰিব পাৰে৷"</string>
+ <string name="save_password_message" msgid="767344687139195790">"ব্ৰাউজাৰে এই পাছৱর্ডটো মনত ৰখাটো বিচাৰেনে?"</string>
+ <string name="save_password_notnow" msgid="6389675316706699758">"এতিয়াই নহয়"</string>
+ <string name="save_password_remember" msgid="6491879678996749466">"মনত ৰাখিব"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"কেতিয়াও মনত নাৰাখিব"</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"এই পৃষ্ঠাটো খুলিবলৈ আপোনাৰ অনুমতি নাই।"</string>
+ <string name="text_copied" msgid="4985729524670131385">"ক্লিপব\'র্ডলৈ বাৰ্তা প্ৰতিলিপি কৰা হ\'ল।"</string>
+ <string name="more_item_label" msgid="4650918923083320495">"অধিক"</string>
+ <string name="prepend_shortcut_label" msgid="2572214461676015642">"মেনু+"</string>
+ <string name="menu_space_shortcut_label" msgid="2410328639272162537">"স্পেচ"</string>
+ <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"লিখক"</string>
+ <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"মচক"</string>
+ <string name="search_go" msgid="8298016669822141719">"অনুসন্ধান কৰক"</string>
+ <string name="search_hint" msgid="1733947260773056054">"অনুসন্ধান কৰক…"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"অনুসন্ধান কৰক"</string>
+ <string name="searchview_description_query" msgid="5911778593125355124">"প্ৰশ্নৰ সন্ধান কৰক"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"প্ৰশ্ন মচক"</string>
+ <string name="searchview_description_submit" msgid="2688450133297983542">"প্ৰশ্ন দাখিল কৰক"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"কণ্ঠধ্বনিৰ যোগেৰে সন্ধান কৰক"</string>
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"স্পৰ্শৰে অন্বেষণ কৰা সুবিধা সক্ষম কৰিবনে?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>এ স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰিব বিচাৰে। যেতিয়া স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰা সুবিধা অন কৰা থাকে তেতিয়া আপোনাৰ আঙুলিৰ তলত থকা বিৱৰণবোৰ শুনিব বা চাব পাৰে বা আঙুলিৰ সংকেতৰ জৰিয়তে টেবলেট ব্যৱহাৰ কৰিব পাৰে।"</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>এ স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰিব বিচাৰে। যেতিয়া স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰা সুবিধা অন কৰা থাকে তেতিয়া আপোনাৰ আঙুলিৰ তলত থকা বিৱৰণবোৰ শুনিব বা চাব পাৰে বা আঙুলিৰ ইংগিতৰ জৰিয়তে ফ\'ন ব্যৱহাৰ কৰিব পাৰে।"</string>
+ <string name="oneMonthDurationPast" msgid="7396384508953779925">"১ মাহ আগত"</string>
+ <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"১ মাহতকৈও আগত"</string>
+ <!-- no translation found for last_num_days (5104533550723932025) -->
+ <string name="last_month" msgid="3959346739979055432">"যোৱা মাহ"</string>
+ <string name="older" msgid="5211975022815554840">"পুৰণি"</string>
+ <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> তাৰিখে"</string>
+ <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> বজাত"</string>
+ <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> চনত"</string>
+ <string name="day" msgid="8144195776058119424">"দিন"</string>
+ <string name="days" msgid="4774547661021344602">"দিনবোৰ"</string>
+ <string name="hour" msgid="2126771916426189481">"ঘণ্টা"</string>
+ <string name="hours" msgid="894424005266852993">"ঘণ্টা"</string>
+ <string name="minute" msgid="9148878657703769868">"মিনিট"</string>
+ <string name="minutes" msgid="5646001005827034509">"কেইমিনিটমান"</string>
+ <string name="second" msgid="3184235808021478">"ছেকেণ্ড"</string>
+ <string name="seconds" msgid="3161515347216589235">"কেইছেকেণ্ডমান"</string>
+ <string name="week" msgid="5617961537173061583">"সপ্তাহ"</string>
+ <string name="weeks" msgid="6509623834583944518">"কেইসপ্তাহমান"</string>
+ <string name="year" msgid="4001118221013892076">"বছৰ"</string>
+ <string name="years" msgid="6881577717993213522">"কেইবছৰমান"</string>
+ <string name="now_string_shortest" msgid="8912796667087856402">"এতিয়া"</string>
+ <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> মিনিট</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> মিনিট</item>
+ </plurals>
+ <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টা</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টা</item>
+ </plurals>
+ <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> দিন</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> দিন</item>
+ </plurals>
+ <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> বছৰ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> বছৰ</item>
+ </plurals>
+ <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> মিনিটত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> মিনিটত</item>
+ </plurals>
+ <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টাত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টাত</item>
+ </plurals>
+ <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> দিনত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> দিনত</item>
+ </plurals>
+ <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> বছৰত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> বছৰত</item>
+ </plurals>
+ <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> মিনিটৰ আগত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> মিনিটৰ আগত</item>
+ </plurals>
+ <plurals name="duration_hours_relative" formatted="false" msgid="676894109982008411">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টাৰ আগত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টাৰ আগত</item>
+ </plurals>
+ <plurals name="duration_days_relative" formatted="false" msgid="2203515825765397130">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> দিন আগত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> দিন আগত</item>
+ </plurals>
+ <plurals name="duration_years_relative" formatted="false" msgid="4820062134188885734">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> বছৰৰ আগতে</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> বছৰৰ আগতে</item>
+ </plurals>
+ <plurals name="duration_minutes_relative_future" formatted="false" msgid="4655043589817680966">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> মিনিটত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> মিনিটত</item>
+ </plurals>
+ <plurals name="duration_hours_relative_future" formatted="false" msgid="8084579714205223891">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টাত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ঘণ্টাত</item>
+ </plurals>
+ <plurals name="duration_days_relative_future" formatted="false" msgid="333215369363433992">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> দিনত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> দিনত</item>
+ </plurals>
+ <plurals name="duration_years_relative_future" formatted="false" msgid="8644862986413104011">
+ <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> বছৰত</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> বছৰত</item>
+ </plurals>
+ <string name="VideoView_error_title" msgid="3534509135438353077">"ভিডিঅ\'ত সমস্যা আছে"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"এই ভিডিঅ\'টোক এই ডিভাইচটোত ষ্ট্ৰীমিং কৰিবৰ বাবে মান্য নহয়।"</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"এই ভিডিঅ\' প্লে কৰিব পৰা নাযায়।"</string>
+ <string name="VideoView_error_button" msgid="2822238215100679592">"ঠিক আছে"</string>
+ <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon" msgid="7245353528818587908">"দুপৰীয়া"</string>
+ <string name="Noon" msgid="3342127745230013127">"দুপৰীয়া"</string>
+ <string name="midnight" msgid="7166259508850457595">"মাজনিশা"</string>
+ <string name="Midnight" msgid="5630806906897892201">"মাজনিশা"</string>
+ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll" msgid="6876518925844129331">"সকলো বাছনি কৰক"</string>
+ <string name="cut" msgid="3092569408438626261">"কাটক"</string>
+ <string name="copy" msgid="2681946229533511987">"প্ৰতিলিপি কৰক"</string>
+ <string name="failed_to_copy_to_clipboard" msgid="1833662432489814471">"ক্লিপব\'ৰ্ডত প্ৰতিলিপি কৰিব পৰা নগ\'ল"</string>
+ <string name="paste" msgid="5629880836805036433">"পেইষ্ট কৰক"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"নিকা পাঠ হিচাপে পেইষ্ট কৰক"</string>
+ <string name="replace" msgid="5781686059063148930">"সলনি কৰক…"</string>
+ <string name="delete" msgid="6098684844021697789">"মচক"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"URL প্ৰতিলিপি কৰক"</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"পাঠ বাছনি কৰক"</string>
+ <string name="undo" msgid="7905788502491742328">"আনডু কৰক"</string>
+ <string name="redo" msgid="7759464876566803888">"ৰিডু"</string>
+ <string name="autofill" msgid="3035779615680565188">"স্বয়ংপূৰ্তি"</string>
+ <string name="textSelectionCABTitle" msgid="5236850394370820357">"বাৰ্তা বাছনি"</string>
+ <string name="addToDictionary" msgid="4352161534510057874">"অভিধানত যোগ কৰক"</string>
+ <string name="deleteText" msgid="6979668428458199034">"মচক"</string>
+ <string name="inputMethod" msgid="1653630062304567879">"ইনপুট পদ্ধতি"</string>
+ <string name="editTextMenuTitle" msgid="4909135564941815494">"পাঠ বিষয়ক কাৰ্য"</string>
+ <string name="email" msgid="4560673117055050403">"ইমেইল"</string>
+ <string name="dial" msgid="1253998302767701559">"কল কৰক"</string>
+ <string name="map" msgid="6521159124535543457">"অৱস্থান নিৰূপণ কৰক"</string>
+ <string name="browse" msgid="1245903488306147205">"খোলক"</string>
+ <string name="sms" msgid="4560537514610063430">"বাৰ্তা"</string>
+ <string name="add_contact" msgid="7867066569670597203">"যোগ দিয়ক"</string>
+ <!-- no translation found for view_calendar (979609872939597838) -->
+ <skip />
+ <!-- no translation found for add_calendar_event (1953664627192056206) -->
+ <skip />
+ <!-- no translation found for view_flight (7691640491425680214) -->
+ <skip />
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"সঞ্চয়াগাৰৰ খালী ঠাই শেষ হৈ আছে"</string>
+ <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ছিষ্টেমৰ কিছুমান কাৰ্যকলাপে কাম নকৰিবও পাৰে"</string>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ছিষ্টেমৰ বাবে পৰ্যাপ্ত খালী ঠাই নাই। আপোনাৰ ২৫০এম. বি. খালী ঠাই থকাটো নিশ্চিত কৰক আৰু ৰিষ্টাৰ্ট কৰক।"</string>
+ <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> চলি আছে"</string>
+ <string name="app_running_notification_text" msgid="1197581823314971177">"অধিক তথ্য জানিবলৈ বা এপ বন্ধ কৰিবলৈ টিপক।"</string>
+ <string name="ok" msgid="5970060430562524910">"ঠিক আছে"</string>
+ <string name="cancel" msgid="6442560571259935130">"বাতিল কৰক"</string>
+ <string name="yes" msgid="5362982303337969312">"ঠিক আছে"</string>
+ <string name="no" msgid="5141531044935541497">"বাতিল কৰক"</string>
+ <string name="dialog_alert_title" msgid="2049658708609043103">"মনোযোগ দিব"</string>
+ <string name="loading" msgid="7933681260296021180">"ল\'ড কৰি থকা হৈছে…"</string>
+ <string name="capital_on" msgid="1544682755514494298">"অন কৰক"</string>
+ <string name="capital_off" msgid="6815870386972805832">"অফ কৰক"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string>
+ <string name="whichApplicationNamed" msgid="8260158865936942783">"%1$s ব্যৱহাৰ কৰি কাৰ্যটো সম্পূৰ্ণ কৰক"</string>
+ <string name="whichApplicationLabel" msgid="7425855495383818784">"কাৰ্য সম্পূৰ্ণ কৰক"</string>
+ <string name="whichViewApplication" msgid="3272778576700572102">"ইয়াৰ জৰিয়তে খোলক"</string>
+ <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sৰ জৰিয়তে খোলক"</string>
+ <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খোলক"</string>
+ <string name="whichEditApplication" msgid="144727838241402655">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
+ <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sৰদ্বাৰা সম্পাদনা কৰক"</string>
+ <string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা কৰক"</string>
+ <string name="whichSendApplication" msgid="6902512414057341668">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+ <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$sৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+ <string name="whichSendApplicationLabel" msgid="4579076294675975354">"শ্বেয়াৰ কৰক"</string>
+ <string name="whichSendToApplication" msgid="8272422260066642057">"ইয়াৰ মাধ্য়মেৰে প্ৰেৰণ কৰক"</string>
+ <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ব্য়ৱহাৰ কৰি প্ৰেৰণ কৰক"</string>
+ <string name="whichSendToApplicationLabel" msgid="8878962419005813500">"প্রেৰণ কৰক"</string>
+ <string name="whichHomeApplication" msgid="4307587691506919691">"এটা হ\'ম এপ্ বাছনি কৰক"</string>
+ <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"হ\'ম ৰূপে %1$s ব্যৱহাৰ কৰক"</string>
+ <string name="whichHomeApplicationLabel" msgid="809529747002918649">"প্ৰতিচ্ছবি তোলক"</string>
+ <string name="whichImageCaptureApplication" msgid="3680261417470652882">"ইয়াৰ সৈতে প্ৰতিচ্ছবি তোলক"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"%1$s ৰ সৈতে প্ৰতিচ্ছবি তোলক"</string>
+ <string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"প্ৰতিচ্ছবি তোলক"</string>
+ <string name="alwaysUse" msgid="4583018368000610438">"এই কার্যৰ বাবে পূর্বনির্ধাৰিত ধৰণে ব্যৱহাৰ কৰক।"</string>
+ <string name="use_a_different_app" msgid="8134926230585710243">"এটা পৃথক এপ্ ব্যৱহাৰ কৰক"</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"ছিষ্টেমৰ ছেটিংসমূহ > এপসমূহ > ডাউনল\'ড কৰা সমল-লৈ গৈ ডিফ\'ল্ট মচক৷"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"কোনো কার্য বাছনি কৰক"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"ইউএছবি ডিভাইচৰ বাবে এটা এপ্ বাছনি কৰক"</string>
+ <string name="noApplications" msgid="2991814273936504689">"কোনো এপে এই কাৰ্য কৰিব নোৱাৰে।"</string>
+ <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> বন্ধ হ\'ল"</string>
+ <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> বন্ধ হ\'ল"</string>
+ <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> বাৰে বাৰে বন্ধ হৈ গৈছে"</string>
+ <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> বাৰে বাৰে বন্ধ হৈ গৈছে"</string>
+ <string name="aerr_restart" msgid="7581308074153624475">"আকৌ এপটো খোলক"</string>
+ <string name="aerr_report" msgid="5371800241488400617">"আপোনাৰ প্ৰতিক্ৰিয়া পঠিয়াওক"</string>
+ <string name="aerr_close" msgid="2991640326563991340">"বন্ধ কৰক"</string>
+ <string name="aerr_mute" msgid="1974781923723235953">"ডিভাইচ ৰিষ্টাৰ্ট নোহোৱালৈ মিউট কৰক"</string>
+ <string name="aerr_wait" msgid="3199956902437040261">"অপেক্ষা কৰক"</string>
+ <string name="aerr_close_app" msgid="3269334853724920302">"এপটো বন্ধ কৰক"</string>
+ <string name="anr_title" msgid="4351948481459135709"></string>
+ <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g>য়ে সঁহাৰি দিয়া নাই"</string>
+ <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g>য়ে সঁহাৰি দিয়া নাই"</string>
+ <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g>য়ে সঁহাৰি দিয়া নাই"</string>
+ <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> প্ৰক্ৰিয়াই সঁহাৰি দিয়া নাই"</string>
+ <string name="force_close" msgid="8346072094521265605">"ঠিক আছে"</string>
+ <string name="report" msgid="4060218260984795706">"অভিযোগ কৰক"</string>
+ <string name="wait" msgid="7147118217226317732">"অপেক্ষা কৰক"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"এই পৃষ্ঠাই কোনো সহাঁৰি জনোৱা নাই।\n\nআপুনি ইয়াক বন্ধ কৰিব বিচাৰেনে?"</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"আন এটা এপৰ ওপৰত"</string>
+ <string name="launch_warning_replace" msgid="6202498949970281412">"এতিয়া <xliff:g id="APP_NAME">%1$s</xliff:g> চলি আছে।"</string>
+ <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক পূৰ্বতে লঞ্চ কৰা হৈছিল৷"</string>
+ <string name="screen_compat_mode_scale" msgid="3202955667675944499">"স্কেল"</string>
+ <string name="screen_compat_mode_show" msgid="4013878876486655892">"সদায় দেখুৱাওক"</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"ছিষ্টেমৰ ছেটিংসমূহ > এপসমূহ > ডাউনল\'ড কৰা সমল-লৈ গৈ ইয়াক আকৌ সক্ষম কৰক।"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বর্তমানৰ ডিছপ্লেৰ আকাৰ ছেটিং ব্যৱহাৰ কৰিব নোৱাৰে আৰু ই সঠিকভাৱে নচলিবও পাৰে।"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"সদায় দেখুৱাওক"</string>
+ <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক এটা খাপ নোখোৱা Android OS সংস্কৰণৰ বাবে তৈয়াৰ কৰা হৈছিল, যাৰ ফলত ই অস্বাভাৱিকধৰণে আচৰণ কৰিব পাৰে। এপটোৰ শেহতীয়া সংস্কৰণ উপলব্ধ হ\'ব পাৰে।"</string>
+ <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"সদায় দেখুৱাওক"</string>
+ <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"আপডেট আছে নেকি চাওক"</string>
+ <string name="smv_application" msgid="3307209192155442829">"এপটোৱে <xliff:g id="APPLICATION">%1$s</xliff:g> (প্ৰক্ৰিয়াটোৱে <xliff:g id="PROCESS">%2$s</xliff:g>) নিজে বলবৎ কৰা StrictMode নীতি ভংগ কৰিলে।"</string>
+ <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> প্ৰক্ৰিয়াটোৱে নিজে বলৱৎ কৰা StrictMode নীতি ভংগ কৰিলে।"</string>
+ <!-- no translation found for android_upgrading_title (7513829952443484438) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (4503169817302593560) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (7009520271220804517) -->
+ <skip />
+ <!-- no translation found for android_start_title (4536778526365907780) -->
+ <skip />
+ <!-- no translation found for android_start_title (4929837533850340472) -->
+ <skip />
+ <!-- no translation found for android_start_title (7467484093260449437) -->
+ <skip />
+ <string name="android_upgrading_fstrim" msgid="8036718871534640010">"সঞ্চয়াগাৰ অপ্টিমাইজ কৰি থকা হৈছে।"</string>
+ <!-- no translation found for android_upgrading_notification_title (1511552415039349062) -->
+ <skip />
+ <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক আপগ্ৰেড কৰি থকা হৈছে…"</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>ৰ ভিতৰত <xliff:g id="NUMBER_0">%1$d</xliff:g> এপ্ অপ্টিমাইজ কৰি থকা হৈছে৷"</string>
+ <!-- no translation found for android_preparing_apk (8162599310274079154) -->
+ <skip />
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"আৰম্ভ হৈ থকা এপসমূহ।"</string>
+ <string name="android_upgrading_complete" msgid="1405954754112999229">"বুট কাৰ্য সমাপ্ত কৰিছে।"</string>
+ <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> চলি আছে"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
+ <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+ <skip />
+ <string name="dump_heap_notification_detail" msgid="6901391084243999274">"হীপ ডাম্প সংগ্ৰহ কৰা হ\'ল। শ্বেয়াৰ কৰিবলৈ টিপক"</string>
+ <!-- no translation found for dump_heap_title (5864292264307651673) -->
+ <skip />
+ <!-- no translation found for dump_heap_text (4809417337240334941) -->
+ <skip />
+ <string name="sendText" msgid="5209874571959469142">"বার্তাৰ বাবে কাৰ্য বাছনি কৰক"</string>
+ <string name="volume_ringtone" msgid="6885421406845734650">"ৰিংগাৰৰ ধ্বনি"</string>
+ <string name="volume_music" msgid="5421651157138628171">"মিডিয়াৰ ধ্বনি"</string>
+ <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"ব্লুটুথৰ জৰিয়তে প্লে কৰি থকা হৈছে"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"ৰিংট\'ন নিৰৱ ম\'ডত ছেট কৰা আছে"</string>
+ <string name="volume_call" msgid="3941680041282788711">"কলৰ সময়ত ধ্বনিৰ মাত্ৰা"</string>
+ <string name="volume_bluetooth_call" msgid="2002891926351151534">"ব্লুটুথৰ যোগেৰে কৰা কলৰ সময়ত ধ্বনিৰ মাত্ৰা"</string>
+ <string name="volume_alarm" msgid="1985191616042689100">"এলার্মৰ ধ্বনি"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"জাননীৰ ধ্বনি"</string>
+ <string name="volume_unknown" msgid="1400219669770445902">"ধ্বনি"</string>
+ <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"ব্লুটুথৰ ভলিউম"</string>
+ <string name="volume_icon_description_ringer" msgid="3326003847006162496">"ৰিংট\'নৰ ধ্বনি"</string>
+ <string name="volume_icon_description_incall" msgid="8890073218154543397">"কলৰ ভলিউম"</string>
+ <string name="volume_icon_description_media" msgid="4217311719665194215">"মিডিয়াৰ ভলিউম"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"জাননীৰ ধ্বনি"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"পূর্বনিধার্ৰিত ৰিংট\'ন"</string>
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"ডিফ\'ল্ট (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent" msgid="7937634392408977062">"একো নাই"</string>
+ <string name="ringtone_picker_title" msgid="3515143939175119094">"ৰিংট\'নসমূহ"</string>
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"এলার্মৰ ধ্বনিসমূহ"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"জাননীৰ ধ্বনিসমূহ"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"অজ্ঞাত"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
+ <item quantity="other">ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">পাছৱৰ্ড অবিহনে সংযোগ কৰিব পৰা ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
+ <item quantity="other">পাছৱৰ্ড অবিহনে সংযোগ কৰিব পৰা ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
+ </plurals>
+ <string name="wifi_available_title" msgid="3817100557900599505">"পাছৱৰ্ড অবিহনে সংযোগ কৰিবপৰা ৱাই-ফাই নেটৱর্কৰ সৈতে সংযোগ কৰক"</string>
+ <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
+ <skip />
+ <string name="wifi_available_title_connecting" msgid="1557292688310330032">"পাছৱৰ্ড অবিহনে সংযোগ কৰিবপৰা ৱাই-ফাই নেটৱর্কৰ সৈতে সংযোগ কৰি থকা হৈছে"</string>
+ <string name="wifi_available_title_connected" msgid="7542672851522241548">"ৱাই-ফাই নেটৱৰ্কৰ সৈতে সংযোগ কৰা হ\'ল"</string>
+ <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ৱাই-ফাই নেটৱৰ্কৰ সৈতে সংযোগ কৰিবপৰা নগ\'ল"</string>
+ <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"সকলো নেটৱৰ্ক চাবলৈ টিপক"</string>
+ <string name="wifi_available_action_connect" msgid="2635699628459488788">"সংযোগ কৰক"</string>
+ <!-- no translation found for wifi_available_action_all_networks (4368435796357931006) -->
+ <skip />
+ <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে অন হ\'ব"</string>
+ <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"যেতিয়া আপুনি ছেভ কৰি থোৱা উচ্চ মানৰ নেটৱৰ্কৰ কাষত থাকে"</string>
+ <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"পুনৰাই অন নকৰিব"</string>
+ <!-- no translation found for wifi_wakeup_enabled_title (6534603733173085309) -->
+ <skip />
+ <!-- no translation found for wifi_wakeup_enabled_content (189330154407990583) -->
+ <skip />
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"</string>
+ <!-- no translation found for network_available_sign_in (1848877297365446605) -->
+ <skip />
+ <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
+ <skip />
+ <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইন্টাৰনেট নাই"</string>
+ <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"অধিক বিকল্পৰ বাবে টিপক"</string>
+ <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ\'ল"</string>
+ <string name="network_switch_metered_detail" msgid="775163331794506615">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
+ <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ\'ল"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="3979506840912951943">"ম\'বাইল ডেটা"</item>
+ <item msgid="75483255295529161">"ৱাই-ফাই"</item>
+ <item msgid="6862614801537202646">"ব্লুটুথ"</item>
+ <item msgid="5447331121797802871">"ইথাৰনেট"</item>
+ <item msgid="8257233890381651999">"ভিপিএন"</item>
+ </string-array>
+ <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"অজ্ঞাত প্ৰকাৰৰ নেটৱৰ্ক"</string>
+ <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ৱাই-ফাইৰ লগত সংযোগ কৰিব পৰা নগ\'ল"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ইণ্টাৰনেট সংযোগ যথেষ্ট দুর্বল।"</string>
+ <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগ কৰাৰ অনুমতি দিবনে?"</string>
+ <!-- no translation found for wifi_connect_alert_message (6451273376815958922) -->
+ <skip />
+ <string name="wifi_connect_default_application" msgid="7143109390475484319">"এপ্লিকেশ্বন"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ৱাই-ফাই ডাইৰেক্ট"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ৱাই-ফাই ডাইৰেক্ট আৰম্ভ কৰক। এই কার্যই ৱাই-ফাই ক্লাইণ্ট/হ\'টস্প\'ট অফ কৰিব।"</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ৱাই-ফাই ডাইৰেক্ট আৰম্ভ কৰিব পৰা নগ\'ল।"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ৱাই-ফাই ডাইৰেক্ট অন হৈ আছে"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ছেটিংসমূহৰ বাবে টিপক"</string>
+ <string name="accept" msgid="1645267259272829559">"স্বীকাৰ কৰক"</string>
+ <string name="decline" msgid="2112225451706137894">"প্ৰত্যাখ্যান কৰক"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"আমন্ত্ৰণ পঠোৱা হ\'ল"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"সংযোগ হ\'বলৈ আমন্ত্ৰণ"</string>
+ <string name="wifi_p2p_from_message" msgid="570389174731951769">"প্ৰেৰক:"</string>
+ <string name="wifi_p2p_to_message" msgid="248968974522044099">"প্ৰতি:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"প্ৰয়োজনীয় পিন নম্বৰটো লিখক:"</string>
+ <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"পিন:"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"টি.ভি.টো <xliff:g id="DEVICE_NAME">%1$s</xliff:g> লৈ সংযোগ হৈ থকাৰ অৱস্থাত অস্থায়ীভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ\'ব"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"টিভিটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ লগত সংযোগ হ\'লে সাময়িকভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ\'ব"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ফ\'নটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g> লৈ সংযোগ হ\'লে ৱাই-ফাইৰ পৰা কিছু সময়ৰ বাবে সংযোগ স্বীকাৰ বিচ্ছিন্ন হ\'ব"</string>
+ <string name="select_character" msgid="3365550120617701745">"বর্ণ লিখক"</string>
+ <string name="sms_control_title" msgid="7296612781128917719">"এছএমএছ বার্তাবোৰ পঠিয়াই থকা হৈছে"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> এ বহু সংখ্যক এছএমএছ বার্তাবোৰ প্ৰেৰণ কৰি আছে। আপুনি এই এপে বার্তা প্ৰেৰণ কৰি থকাটো বিচাৰেনে?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"অনুমতি দিয়ক"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"অস্বীকাৰ কৰক"</string>
+ <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>এ <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> লৈ কিবা বার্তা প্ৰেৰণ কৰিব বিচাৰিছে।"</string>
+ <string name="sms_short_code_details" msgid="5873295990846059400">"ইয়াৰ বাবে "<b>" মাছুল ভৰিবলগীয়া হ\'ব পাৰে"</b>"।"</string>
+ <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"ইয়াৰ বাবে মাছুল ভৰিবলগীয়া হ\'ব পাৰে।"</b></string>
+ <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"পঠিয়াওক"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"বাতিল কৰক"</string>
+ <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"মোৰ পচন্দ মনত ৰাখিব"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"আপুনি ইয়াক পিছত ছেটিং > এপ্-ত সলনি কৰিব পাৰে"</string>
+ <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"যিকোনো সময়ত অনুমতি দিয়ক"</string>
+ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"কেতিয়াও অনুমতি নিদিব"</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"ছিম কাৰ্ড আঁতৰোৱা হ\'ল"</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"এখন মান্য ছিম কার্ড ব্যৱহাৰ কৰি ৰিষ্টার্ট নকৰা পর্যন্ত ম\'বাইলৰ নেটৱর্ক উপলব্ধ নহয়।"</string>
+ <string name="sim_done_button" msgid="827949989369963775">"সম্পন্ন হ\'ল"</string>
+ <string name="sim_added_title" msgid="3719670512889674693">"ছিম কাৰ্ড যোগ কৰা হ\'ল"</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"ম\'বাইলৰ নেটৱর্ক ব্যৱহাৰ কৰিবলৈ আপোনাৰ ডিভাইচটো ৰিষ্টার্ট কৰক।"</string>
+ <string name="sim_restart_button" msgid="4722407842815232347">"ৰিষ্টাৰ্ট কৰক"</string>
+ <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
+ <skip />
+ <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
+ <skip />
+ <!-- no translation found for install_carrier_app_notification_text_app_name (1196505084835248137) -->
+ <skip />
+ <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
+ <skip />
+ <string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন ছিম ভৰোৱা হৈছে"</string>
+ <string name="carrier_app_notification_text" msgid="1132487343346050225">"ছেট আপ কৰিবলৈ টিপক"</string>
+ <string name="time_picker_dialog_title" msgid="8349362623068819295">"সময় ছেট কৰক"</string>
+ <string name="date_picker_dialog_title" msgid="5879450659453782278">"তাৰিখ ছেট কৰক"</string>
+ <string name="date_time_set" msgid="5777075614321087758">"ছেট কৰক"</string>
+ <string name="date_time_done" msgid="2507683751759308828">"সম্পন্ন হ\'ল"</string>
+ <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"নতুন: "</font></string>
+ <string name="perms_description_app" msgid="5139836143293299417">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ প্ৰদান কৰা"</string>
+ <string name="no_permissions" msgid="7283357728219338112">"কোনো অনুমতিৰ প্ৰয়োজন নাই"</string>
+ <string name="perm_costs_money" msgid="4902470324142151116">"ইয়াৰ ফলত আপোনাৰ টকা খৰচ হ\'ব পাৰে"</string>
+ <string name="dlg_ok" msgid="7376953167039865701">"ঠিক আছে"</string>
+ <!-- no translation found for usb_charging_notification_title (1595122345358177163) -->
+ <skip />
+ <!-- no translation found for usb_supplying_notification_title (4631045789893086181) -->
+ <skip />
+ <!-- no translation found for usb_mtp_notification_title (4238227258391151029) -->
+ <skip />
+ <!-- no translation found for usb_ptp_notification_title (5425857879922006878) -->
+ <skip />
+ <!-- no translation found for usb_tether_notification_title (3716143122035802501) -->
+ <skip />
+ <!-- no translation found for usb_midi_notification_title (5356040379749154805) -->
+ <skip />
+ <!-- no translation found for usb_accessory_notification_title (1899977434994900306) -->
+ <skip />
+ <string name="usb_notification_message" msgid="3370903770828407960">"অধিক বিকল্পৰ বাবে টিপক।"</string>
+ <!-- no translation found for usb_power_notification_message (4647527153291917218) -->
+ <skip />
+ <string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"এনাল\'গ অডিঅ\' সহায়ক সামগ্ৰী পোৱা গৈছে"</string>
+ <string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"সংলগ্ন কৰা ডিভাইচটোৱে এই ফ\'নটোৰ সৈতে কাম কৰিব নোৱাৰে। অধিক জানিবলৈ টিপক।"</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"ইউএছবি ডিবাগিং সংযোগ কৰা হ\'ল"</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"ইউএছবি ডিবাগিং অক্ষম কৰিবলৈ টিপক।"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ইউএছবি ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"বাগ সম্পর্কীয় অভিযোগ গ্ৰহণ কৰি থকা হৈছে…"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"বাগ সম্পর্কীয় অভিযোগ শ্বেয়াৰ কৰিবনে?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"বাগ সম্পর্কীয় অভিযোগ শ্বেয়াৰ কৰি থকা হৈছে…"</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="6029609949340992866">"আপোনাৰ প্ৰশাসকে এই ডিভাইচটোৰ সমস্যা সমাধানৰ বাবে বাগ সম্পৰ্কীয় অভিযোগ বিচাৰিছে। এপ্ আৰু ডেটা শ্বেয়াৰ কৰা হ\'ব পাৰে।"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"শ্বেয়াৰ কৰক"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"প্ৰত্যাখ্যান কৰক"</string>
+ <string name="select_input_method" msgid="8547250819326693584">"কীব\'ৰ্ড সলনি কৰক"</string>
+ <string name="show_ime" msgid="2506087537466597099">"কায়িক কীব’ৰ্ড সক্ৰিয় হৈ থাকোঁতে ইয়াক স্ক্ৰীণত ৰাখিব"</string>
+ <string name="hardware" msgid="194658061510127999">"ভাৰ্শ্বুৱল কীব\'ৰ্ড দেখুৱাওক"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"কায়িক কীব’ৰ্ড কনফিগাৰ কৰক"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা আৰু চানেকি বাছনি কৰিবলৈ ইয়াত টিপক"</string>
+ <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"অন্য এপৰ ওপৰত দেখুৱায়"</string>
+ <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> অন্য এপসমূহৰ ওপৰত প্ৰদৰ্শিত হৈ আছে"</string>
+ <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g>এ অইন এপবোৰৰ ওপৰত প্ৰদৰ্শিত হৈ আছে"</string>
+ <string name="alert_windows_notification_message" msgid="8917232109522912560">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g>এ এই সুবিধাটো ব্যৱহাৰ কৰাটো নিবিচাৰে তেন্তে টিপি ছেটিংসমূহ খোলক আৰু ইয়াক অফ কৰক।"</string>
+ <!-- no translation found for alert_windows_notification_turn_off_action (2902891971380544651) -->
+ <skip />
+ <!-- no translation found for ext_media_checking_notification_title (5734005953288045806) -->
+ <skip />
+ <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"আসোঁৱাহ বিচাৰি থকা হৈছে"</string>
+ <!-- no translation found for ext_media_new_notification_message (7589986898808506239) -->
+ <skip />
+ <!-- no translation found for ext_media_ready_notification_message (4083398150380114462) -->
+ <skip />
+ <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"<xliff:g id="NAME">%s</xliff:g> ব্যৱহাৰযোগ্য নহয়"</string>
+ <string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"<xliff:g id="NAME">%s</xliff:g> ব্যৱহাৰযোগ্য নহয়। সমস্যাটো সমাধান কৰিবলৈ টিপক।"</string>
+ <string name="ext_media_unmountable_notification_message" product="tv" msgid="3941179940297874950">"<xliff:g id="NAME">%s</xliff:g> ব্যৱহাৰযোগ্য হৈ থকা নাই। ঠিক কৰিবলৈ বাছনি কৰক।"</string>
+ <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g>ক ব্যৱহাৰ কৰিব নোৱাৰি"</string>
+ <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"এই ডিভাইচটোৱে <xliff:g id="NAME">%s</xliff:g>ক ব্যৱহাৰ কৰিব নোৱাৰে। ব্যৱহাৰ কৰিব পৰা ফৰ্মেটত ছেট আপ কৰিবলৈ টিপক।"</string>
+ <string name="ext_media_unsupported_notification_message" product="tv" msgid="3725436899820390906">"এই ডিভাইচটোৱে <xliff:g id="NAME">%s</xliff:g>ক চলাব নোৱাৰে। চলাব পৰা কোনো ফৰ্মেটত ছেট আপ কৰিবলৈ বাছনি কৰক।"</string>
+ <!-- no translation found for ext_media_badremoval_notification_title (3206248947375505416) -->
+ <skip />
+ <!-- no translation found for ext_media_badremoval_notification_message (380176703346946313) -->
+ <skip />
+ <!-- no translation found for ext_media_nomedia_notification_title (1704840188641749091) -->
+ <skip />
+ <!-- no translation found for ext_media_nomedia_notification_message (6471542972147056586) -->
+ <skip />
+ <!-- no translation found for ext_media_unmounting_notification_title (640674168454809372) -->
+ <skip />
+ <!-- no translation found for ext_media_unmounting_notification_message (4182843895023357756) -->
+ <skip />
+ <string name="ext_media_init_action" msgid="7952885510091978278">"ছেট আপ কৰক"</string>
+ <!-- no translation found for ext_media_unmount_action (1121883233103278199) -->
+ <skip />
+ <!-- no translation found for ext_media_browse_action (8322172381028546087) -->
+ <skip />
+ <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+ <skip />
+ <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+ <skip />
+ <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+ <skip />
+ <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+ <skip />
+ <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+ <skip />
+ <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+ <skip />
+ <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+ <skip />
+ <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+ <skip />
+ <string name="ext_media_status_removed" msgid="6576172423185918739">"আঁতৰোৱা হ\'ল"</string>
+ <string name="ext_media_status_unmounted" msgid="2551560878416417752">"বাহিৰলৈ উলিওৱা হ\'ল"</string>
+ <string name="ext_media_status_checking" msgid="6193921557423194949">"পৰীক্ষা কৰি থকা হৈছে…"</string>
+ <string name="ext_media_status_mounted" msgid="7253821726503179202">"সাজু"</string>
+ <string name="ext_media_status_mounted_ro" msgid="8020978752406021015">"ৰীড-অনলি"</string>
+ <string name="ext_media_status_bad_removal" msgid="8395398567890329422">"বিপজ্জনকভাৱে আঁতৰোৱা হ\'ল"</string>
+ <string name="ext_media_status_unmountable" msgid="805594039236667894">"ব্যৱহাৰযোগ্য নহয়"</string>
+ <string name="ext_media_status_unsupported" msgid="4691436711745681828">"সঞ্চয়াগাৰ ব্যৱহাৰ কৰিব নোৱাৰি"</string>
+ <string name="ext_media_status_ejecting" msgid="5463887263101234174">"বাহিৰলৈ উলিয়াই থকা হৈছে…"</string>
+ <string name="ext_media_status_formatting" msgid="1085079556538644861">"ফৰ্মেট কৰি থকা হৈছে…"</string>
+ <string name="ext_media_status_missing" msgid="5638633895221670766">"ভৰোৱা নাই"</string>
+ <string name="activity_list_empty" msgid="1675388330786841066">"কোনো মিলা কাৰ্যকলাপ পোৱা নগ\'ল।"</string>
+ <string name="permlab_route_media_output" msgid="6243022988998972085">"মিডিয়াৰ আউটপুট ৰাউট কৰিব পাৰে"</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"অন্য় বাহ্যিক ডিভাইচবোৰলৈ মিডিয়া আউটপুট প্ৰেৰণ কৰিবলৈ এপ্লিকেশ্বনক অনুমতি দিয়ে।"</string>
+ <string name="permlab_readInstallSessions" msgid="3713753067455750349">"ইনষ্টল কৰা ছেশ্বনসমূহ পঢ়িব পাৰে"</string>
+ <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"এটা এপ্লিকেশ্বনক ইনষ্টল কৰা ছেশ্বনসমূহ পঢ়িবলৈ অনুমতি দিয়ে। এই কাৰ্যই সক্ৰিয় পেকেজ ইনষ্টলেশ্বনৰ বিষয়ে চাবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"পেকেজ ইনষ্টলৰ বাবে অনুৰোধ কৰিব পাৰে"</string>
+ <!-- no translation found for permdesc_requestInstallPackages (5740101072486783082) -->
+ <skip />
+ <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"পেকেজ মচাৰ অনুৰোধ কৰিব পাৰে"</string>
+ <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"এপটোক পেকেজবোৰ মচাৰ অনুৰোধ কৰিবলৈ দিয়ে।"</string>
+ <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"বেটাৰি অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ বিচাৰক"</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"কোনো এপক সেই এপটোৰ বাবে বেটাৰি অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ অনুমতি বিচাৰিবলৈ দিয়ে।"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"জুম নিয়ন্ত্ৰণ কৰিবলৈ দুবাৰ টিপক"</string>
+ <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ৱিজেট যোগ কৰিব পৰা নগ\'ল।"</string>
+ <string name="ime_action_go" msgid="8320845651737369027">"যাওক"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"অনুসন্ধান কৰক"</string>
+ <string name="ime_action_send" msgid="2316166556349314424">"পঠিয়াওক"</string>
+ <string name="ime_action_next" msgid="3138843904009813834">"পৰৱৰ্তী"</string>
+ <string name="ime_action_done" msgid="8971516117910934605">"সম্পন্ন হ\'ল"</string>
+ <string name="ime_action_previous" msgid="1443550039250105948">"আগৰ"</string>
+ <string name="ime_action_default" msgid="2840921885558045721">"কার্য কৰক"</string>
+ <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g> ব্যৱহাৰ কৰি \n নম্বৰটো ডায়েল কৰক"</string>
+ <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g> ব্যৱহাৰ কৰি সম্পৰ্ক \n সৃষ্টি কৰক"</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"বৰ্তমান আৰু ভৱিষ্যতে আপোনাৰ একাউণ্টত প্ৰৱেশ কৰিবলৈ তলৰ এটা বা অধিক এপে অনুমতি লাভৰ বাবে অনুৰোধ কৰিছে৷"</string>
+ <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"আপুনি এই অনুৰোধক সন্মতি দিব বিচাৰেনে?"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"ব্য়ৱহাৰ কৰাৰ অনুমতি বিচাৰি কৰা অনুৰোধ"</string>
+ <string name="allow" msgid="7225948811296386551">"অনুমতি দিয়ক"</string>
+ <string name="deny" msgid="2081879885755434506">"প্ৰত্যাখ্যান কৰক"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"অনুমতি বিচাৰি অনুৰোধ কৰা হৈছে"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> একাউণ্টৰ বাবে\nঅনুমতি বিচাৰি অনুৰোধ কৰা হৈছে।"</string>
+ <string name="forward_intent_to_owner" msgid="1207197447013960896">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ বাহিৰত এই এপটো ব্যৱহাৰ কৰি আছে"</string>
+ <string name="forward_intent_to_work" msgid="621480743856004612">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ ভিতৰত এই এপটো ব্যৱহাৰ কৰি আছে"</string>
+ <string name="input_method_binding_label" msgid="1283557179944992649">"ইনপুট পদ্ধতি"</string>
+ <string name="sync_binding_label" msgid="3687969138375092423">"ছিংক"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"দিব্যাংগসকলৰ বাবে থকা সুবিধাসমূহ"</string>
+ <string name="wallpaper_binding_label" msgid="1240087844304687662">"ৱালপেপাৰ"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"ৱালপেপাৰ সলনি কৰক"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"জাননী নিৰীক্ষক"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR শ্ৰোতা"</string>
+ <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"অৱস্থা প্ৰদানকাৰী"</string>
+ <string name="notification_ranker_binding_label" msgid="774540592299064747">"জাননীৰ স্তৰ নিৰ্দ্ধাৰক সেৱা"</string>
+ <string name="vpn_title" msgid="19615213552042827">"ভিপিএন সক্ৰিয় কৰা হৈছে"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>এ ভিপিএন সক্ৰিয় কৰিলে"</string>
+ <string name="vpn_text" msgid="1610714069627824309">"নেটৱর্ক পৰিচালনা কৰিবলৈ টিপক।"</string>
+ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>ৰ সৈতে সংযোগ হৈছে। নেটৱর্ক পৰিচালনা কৰিবলৈ টিপক।"</string>
+ <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"সদা-সক্ৰিয় ভিপিএন সংযোগ কৰি থকা হৈছে…"</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"সদা-সক্ৰিয় ভিপিএন সংযোগ কৰা হ\'ল"</string>
+ <string name="vpn_lockdown_disconnected" msgid="735805531187559719">"সদা-সক্ৰিয় ভিপিএনৰ লগত সংযোগ বিচ্ছিন্ন কৰা হৈছে"</string>
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"সদা-সক্ৰিয় ভিপিএনত আসোঁৱাহ"</string>
+ <string name="vpn_lockdown_config" msgid="8151951501116759194">"নেটৱৰ্ক বা ভিপিএন ছেটিংসমূহ সলনি কৰক"</string>
+ <string name="upload_file" msgid="2897957172366730416">"ফাইল বাছনি কৰক"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"কোনো ফাইল বাছনি কৰা হোৱা নাই"</string>
+ <string name="reset" msgid="2448168080964209908">"ৰিছেট কৰক"</string>
+ <string name="submit" msgid="1602335572089911941">"দাখিল কৰক"</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"গাড়ীৰ ম’ড সক্ষম কৰা হ\'ল"</string>
+ <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"গাড়ীৰ ম\'ডৰ পৰা বাহিৰ হ\'বলৈ টিপক।"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ছেট আপ কৰিবলৈ টিপক।"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"টেডাৰিং অক্ষম কৰি থোৱা হৈছে"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"</string>
+ <string name="back_button_label" msgid="2300470004503343439">"উভতি যাওক"</string>
+ <string name="next_button_label" msgid="1080555104677992408">"পৰৱৰ্তী"</string>
+ <string name="skip_button_label" msgid="1275362299471631819">"এৰি যাওক"</string>
+ <string name="no_matches" msgid="8129421908915840737">"কোনো মিল নাই"</string>
+ <string name="find_on_page" msgid="1946799233822820384">"পৃষ্ঠাত বিচাৰক"</string>
+ <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+ <item quantity="one"><xliff:g id="TOTAL">%d</xliff:g>ৰ <xliff:g id="INDEX">%d</xliff:g>টা</item>
+ <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g>ৰ <xliff:g id="INDEX">%d</xliff:g>টা</item>
+ </plurals>
+ <string name="action_mode_done" msgid="7217581640461922289">"সম্পন্ন হ\'ল"</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"ইউএছবি সঞ্চয়াগাৰৰ ডেটা মচি থকা হৈছে…"</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"এছডি কাৰ্ডৰ ডেটা মচি থকা হৈছে…"</string>
+ <string name="share" msgid="1778686618230011964">"শ্বেয়াৰ কৰক"</string>
+ <string name="find" msgid="4808270900322985960">"বিচাৰক"</string>
+ <string name="websearch" msgid="4337157977400211589">"ৱেবত সন্ধান কৰক"</string>
+ <string name="find_next" msgid="5742124618942193978">"পৰৱৰ্তী বস্তু বিচাৰক"</string>
+ <string name="find_previous" msgid="2196723669388360506">"আগৰটো বিচাৰক"</string>
+ <string name="gpsNotifTicker" msgid="5622683912616496172">"<xliff:g id="NAME">%s</xliff:g>ৰ পৰা অৱস্থানৰ অনুৰোধ কৰা হৈছে"</string>
+ <string name="gpsNotifTitle" msgid="5446858717157416839">"অৱস্থানৰ অনুৰোধ"</string>
+ <string name="gpsNotifMessage" msgid="1374718023224000702">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)এ অনুৰোধ কৰিছে"</string>
+ <string name="gpsVerifYes" msgid="2346566072867213563">"হয়"</string>
+ <string name="gpsVerifNo" msgid="1146564937346454865">"নহয়"</string>
+ <string name="sync_too_many_deletes" msgid="5296321850662746890">"মচি পেলোৱাৰ সীমা পাৰ হ\'ল"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"এই <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> ৰ মচি থোৱা <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> টা <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> বস্তু আছে। আপুনি কি কৰিব বিচাৰে?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"বস্তুবোৰ মচক"</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"মচা কাৰ্যক আনডু কৰক"</string>
+ <string name="sync_do_nothing" msgid="3743764740430821845">"এতিয়া একো নকৰিব"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"একাউণ্ট বাছনি কৰক"</string>
+ <string name="add_account_label" msgid="2935267344849993553">"একাউণ্ট যোগ কৰক"</string>
+ <string name="add_account_button_label" msgid="3611982894853435874">"একাউণ্ট যোগ কৰক"</string>
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"বৃদ্ধি কৰক"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"হ্ৰাস কৰক"</string>
+ <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> স্পর্শ কৰক আৰু হেঁচি ধৰক।"</string>
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"বৃদ্ধি কৰিবলৈ ওপৰলৈ আৰু হ্ৰাস কৰিবলৈ তললৈ শ্লাইড কৰক।"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"মিনিট বৃদ্ধি কৰক"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"মিনিট হ্ৰাস কৰক"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"ঘণ্টা বৃদ্ধি কৰক"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"ঘণ্টা হ্ৰাস কৰক"</string>
+ <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"অপৰাহ্ন ছেট কৰক"</string>
+ <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"পূৰ্বাহ্ন ছেট কৰক"</string>
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"মাহ বৃদ্ধি কৰক"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"মাহ হ্ৰাস কৰক"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"দিন বৃদ্ধি কৰক"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"দিন হ্ৰাস কৰক"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"বছৰ বৃদ্ধি কৰক"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"বছৰ হ্ৰাস কৰক"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"বাতিল কৰক"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"মচক"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"সম্পন্ন হ\'ল"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ম\'ড সলনি"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"শ্বিফ্ট"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"এণ্টাৰ"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"এটা এপ্ বাছনি কৰক"</string>
+ <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> লঞ্চ কৰিব পৰা নগ\'ল"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>ৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"শ্লাইড কৰা হেণ্ডেল৷ স্পৰ্শ কৰক আৰু ধৰি ৰাখক৷"</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"স্ক্ৰীণ আনলক কৰিবলৈ ছোৱাইপ কৰক৷"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"গৃহ পৃষ্ঠালৈ যাওক"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"ওপৰলৈ যাওক"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"অধিক বিকল্প"</string>
+ <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s: %2$s"</string>
+ <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
+ <string name="storage_internal" msgid="3570990907910199483">"শ্বেয়াৰ কৰা আভ্যন্তৰীণ সঞ্চয়াগাৰ"</string>
+ <string name="storage_sd_card" msgid="3282948861378286745">"এছডি কাৰ্ড"</string>
+ <!-- no translation found for storage_sd_card_label (6347111320774379257) -->
+ <skip />
+ <!-- no translation found for storage_usb_drive (6261899683292244209) -->
+ <skip />
+ <!-- no translation found for storage_usb_drive_label (4501418548927759953) -->
+ <skip />
+ <string name="storage_usb" msgid="3017954059538517278">"ইউএছবি সঞ্চয়াগাৰ"</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"সম্পাদনা কৰক"</string>
+ <!-- no translation found for data_usage_warning_title (6499834033204801605) -->
+ <skip />
+ <!-- no translation found for data_usage_warning_body (7340198905103751676) -->
+ <skip />
+ <string name="data_usage_mobile_limit_title" msgid="6561099244084267376">"ম\'বাইল ডেটা ব্যৱাহৰৰ সীমা শেষ হৈছে"</string>
+ <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"ৱাই-ফাই ডেটাৰ সীমাত উপনীত হৈছে"</string>
+ <!-- no translation found for data_usage_limit_body (2908179506560812973) -->
+ <skip />
+ <!-- no translation found for data_usage_mobile_limit_snoozed_title (3171402244827034372) -->
+ <skip />
+ <!-- no translation found for data_usage_wifi_limit_snoozed_title (3547771791046344188) -->
+ <skip />
+ <!-- no translation found for data_usage_limit_snoozed_body (1671222777207603301) -->
+ <skip />
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"নেপথ্য ডেটা সীমিত কৰি ৰখা হৈছে৷"</string>
+ <string name="data_usage_restricted_body" msgid="469866376337242726">"সীমাবদ্ধতা আঁতৰাবলৈ টিপক।"</string>
+ <!-- no translation found for data_usage_rapid_title (1809795402975261331) -->
+ <skip />
+ <!-- no translation found for data_usage_rapid_body (6897825788682442715) -->
+ <skip />
+ <!-- no translation found for data_usage_rapid_app_body (5396680996784142544) -->
+ <skip />
+ <string name="ssl_certificate" msgid="6510040486049237639">"নিৰাপত্তা সম্পৰ্কীয় প্ৰমাণপত্ৰ"</string>
+ <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"এই প্ৰমাণপত্ৰখন মান্য৷"</string>
+ <string name="issued_to" msgid="454239480274921032">"প্ৰদান কৰা হৈছে:"</string>
+ <string name="common_name" msgid="2233209299434172646">"সাধাৰণ নাম:"</string>
+ <string name="org_name" msgid="6973561190762085236">"সংস্থা:"</string>
+ <string name="org_unit" msgid="7265981890422070383">"সংস্থাৰ গোট:"</string>
+ <string name="issued_by" msgid="2647584988057481566">"এয়া প্ৰদান কৰে:"</string>
+ <string name="validity_period" msgid="8818886137545983110">"মান্যতা:"</string>
+ <string name="issued_on" msgid="5895017404361397232">"প্ৰদান কৰা সময়:"</string>
+ <string name="expires_on" msgid="3676242949915959821">"ম্যাদ উকলিব:"</string>
+ <string name="serial_number" msgid="758814067660862493">"ক্ৰমিক নম্বৰ:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"ফিংগাৰপ্ৰিণ্ট:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 ফিংগাৰপ্ৰিণ্ট:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 ফিংগাৰপ্ৰিণ্ট:"</string>
+ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"সকলো চাওক"</string>
+ <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"কাৰ্যকলাপ বাছনি কৰক"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
+ <string name="sending" msgid="3245653681008218030">"পঠিয়াই থকা হৈছে…"</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"ব্ৰাউজাৰ লঞ্চ কৰিবনে?"</string>
+ <string name="SetupCallDefault" msgid="5834948469253758575">"কল স্বীকাৰ কৰিবনে?"</string>
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"সদায়"</string>
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"মাত্ৰ এবাৰ"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sএ কৰ্মস্থানৰ প্ৰ\'ফাইল সমৰ্থন নকৰে।"</string>
+ <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"টেবলেট"</string>
+ <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
+ <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ফ\'ন"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ড\'ক স্পীকাৰসমূহ"</string>
+ <string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
+ <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"হেডফ\'নবোৰ"</string>
+ <string name="default_audio_route_name_usb" msgid="1234984851352637769">"ইউএছবি"</string>
+ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ছিষ্টেম"</string>
+ <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ব্লুটুথ অডিঅ\'"</string>
+ <string name="wireless_display_route_description" msgid="9070346425023979651">"ৱায়াৰলেচ ডিছপ্লে\'"</string>
+ <string name="media_route_button_content_description" msgid="591703006349356016">"কাষ্ট"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"ডিভাইচৰ লগত সংযোগ কৰক"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ডিভাইচত স্ক্ৰীণ কাষ্ট কৰক"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"ডিভাইচৰ সন্ধান কৰক…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ছেটিংসমূহ"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"বিচ্ছিন্ন কৰক"</string>
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"স্কেন কৰি থকা হৈছে…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"সংযোগ কৰি থকা হৈছে..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"উপলব্ধ"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"উপলব্ধ নহয়"</string>
+ <string name="media_route_status_in_use" msgid="4533786031090198063">"ব্যৱহাৰ হৈ আছে"</string>
+ <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"অন্তৰ্নিমিত স্ক্ৰীণ"</string>
+ <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI স্ক্ৰীণ"</string>
+ <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"অ\'ভাৰলে\' #<xliff:g id="ID">%1$d</xliff:g>"</string>
+ <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<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="6022119702628572080">", সুৰক্ষিত"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"আৰ্হি পাহৰিলেনে"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"ভুল আৰ্হি"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"ভুল পাছৱৰ্ড"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"ভুল পিন"</string>
+ <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="8790651267324125694">
+ <item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> ছেকেণ্ডত আকৌ চেষ্টা কৰক।</item>
+ <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> ছেকেণ্ডত আকৌ চেষ্টা কৰক।</item>
+ </plurals>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"নিজৰ আৰ্হি আঁকক"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ছিমৰ পিন দিয়ক"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"পিন দিয়ক"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"পাছৱৰ্ড দিয়ক"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ছিমখন বর্তমান অক্ষম অৱস্থাত আছে। অব্যাহত ৰাখিবলৈ PUK ক\'ড লিখক। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"ইচ্ছা কৰা পিন ক\'ড লিখক"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"ইচ্ছা কৰা পিন ক\'ড নিশ্চিত কৰক"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ছিম কার্ড আনলক কৰি থকা হৈছে…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ভুল পিন ক\'ড।"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"৪ ৰ পৰা ৮ টা লৈকে সংখ্য়া সন্নিবিষ্ট হোৱা পিন লিখক।"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK ক\'ড ৮টা সংখ্যাৰ হ\'ব লাগিব।"</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"শুদ্ধ PUK ক\'ডটো পুনৰ দিয়ক। বাৰে বাৰে ভুল ক\'ড দিলে ছিমখন স্থায়ীভাৱে অক্ষম হ\'ব।"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"পিন ক\'ড মিলা নাই"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"বহুতবাৰ ভুলকৈ আর্হি অঁকাৰ প্ৰয়াস কৰা হৈছে"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"আনলক কৰিবলৈ নিজৰ Google একাউণ্টৰ জৰিয়তে ছাইন ইন কৰক।"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"ব্যৱহাৰকাৰী (ইমেইল)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"পাছৱৰ্ড"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"ছাইন ইন কৰক"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"ব্যৱহাৰকাৰীৰ অমান্য নাম বা পাছৱর্ড।"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"নিজৰ ব্যৱহাৰকাৰী নাম আৰু পাছৱর্ড পাহৰিলেনে?\n"<b>"google.com/accounts/recovery"</b>" লৈ যাওক।"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"একাউণ্ট পৰীক্ষা কৰি থকা হৈছে…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"আপুনি আপোনাৰ পিন <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="7813713389422226531">"আপুনি আপোনাৰ পাছৱৰ্ড <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="74089475965050805">"আপুনি আপোনাৰ ল\'ক খোলাৰ আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ আঁকিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"আপুনি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ টেবলেটৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰীৰ ডেটা হেৰুৱাব।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"আপুনি টিভিটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টিভিটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু আপুনি সকলো ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"আপুনি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ ফ\'নৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰীৰ ডেটা হেৰুৱাব।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"আপুনি <xliff:g id="NUMBER">%d</xliff:g>বাৰ ভুলকৈ টেবলেটৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। টেবলেটটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"আপুনি টিভিটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। টিভিটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"আপুনি <xliff:g id="NUMBER">%d</xliff:g>বাৰ ভুলকৈ ফ\'নৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। ফ\'নটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"আপুনি আপোনাৰ ল\'ক খোলাৰ আৰ্হিটো <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="tv" msgid="4224651132862313471">"আপুনি টিভিটো আনলক কৰিবলৈ <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="1437638152015574839">"আপুনি আপোনাৰ ল\'ক খোলাৰ আৰ্হিটো <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="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"আঁতৰাওক"</string>
+ <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"অনুমোদিত স্তৰতকৈ ওপৰলৈ ভলিউম বঢ়াব নেকি?\n\nদীৰ্ঘ সময়ৰ বাবে উচ্চ ভলিউমত শুনাৰ ফলত শ্ৰৱণ ক্ষমতাৰ ক্ষতি হ\'ব পাৰে।"</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"শ্বৰ্টকাট অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটামত ৩ ছেকেণ্ডৰ বাবে ছাপ দি থাকিলে দিব্যাংগসকলৰ বাবে থকা সুবিধা এটা আৰম্ভ হ\'ব। \n\n চলিত দিব্যাংগসকলৰ সুবিধা:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপুনি এই সুবিধাটো ছেটিংসমূহ > দিব্যাংগসকলৰ বাবে সুবিধা-লৈ গৈ সলনি কৰিব পাৰে।"</string>
+ <string name="disable_accessibility_shortcut" msgid="627625354248453445">"শ্বৰ্টকাট অফ কৰক"</string>
+ <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"শ্বৰ্টকাট ব্যৱহাৰ কৰক"</string>
+ <string name="color_inversion_feature_name" msgid="4231186527799958644">"ৰং বিপৰীতকৰণ"</string>
+ <string name="color_correction_feature_name" msgid="6779391426096954933">"ৰং শুধৰণী"</string>
+ <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অন কৰিছে"</string>
+ <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অফ কৰিছে"</string>
+ <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"আপুনি দিব্যাংগসকলৰ সুবিধাৰ বুটামটো টিপিলে ব্যৱহাৰ কৰিবলগীয়া কোনো সুবিধা বাছক:"</string>
+ <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"সুবিধাসমূহ সলনি কৰিবলৈ দিব্যাংগসকলৰ সুবিধাৰ বুটামটো স্পৰ্শ কৰি থাকক।"</string>
+ <string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বিবৰ্ধন"</string>
+ <string name="user_switched" msgid="3768006783166984410">"বৰ্তমানৰ ব্যৱহাৰকাৰী <xliff:g id="NAME">%1$s</xliff:g>।"</string>
+ <string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>লৈ সলনি কৰি থকা হৈছে…"</string>
+ <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>ৰ পৰা লগ আউট কৰি থকা হৈছে…"</string>
+ <string name="owner_name" msgid="2716755460376028154">"গৰাকী"</string>
+ <string name="error_message_title" msgid="4510373083082500195">"আসোঁৱাহ"</string>
+ <string name="error_message_change_not_allowed" msgid="1238035947357923497">"আপোনাৰ প্ৰশাসকে এই অৱস্থাটো সলনি কৰিবলৈ অনুমতি নিদিয়ে"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"এই কাৰ্যটো পৰিচালনা কৰিবলৈ কোনো এপ্লিকেশ্বন পোৱা নগ\'ল"</string>
+ <string name="revoke" msgid="5404479185228271586">"প্ৰত্যাহাৰ কৰক"</string>
+ <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
+ <string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
+ <string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
+ <string name="mediasize_iso_a3" msgid="3023213259314236123">"ISO A3"</string>
+ <string name="mediasize_iso_a4" msgid="231745325296873764">"ISO A4"</string>
+ <string name="mediasize_iso_a5" msgid="3484327407340865411">"ISO A5"</string>
+ <string name="mediasize_iso_a6" msgid="4861908487129577530">"ISO A6"</string>
+ <string name="mediasize_iso_a7" msgid="5890208588072936130">"ISO A7"</string>
+ <string name="mediasize_iso_a8" msgid="4319425041085816612">"ISO A8"</string>
+ <string name="mediasize_iso_a9" msgid="4882220529506432008">"ISO A9"</string>
+ <string name="mediasize_iso_a10" msgid="2382866026365359391">"ISO A10"</string>
+ <string name="mediasize_iso_b0" msgid="3651827147402009675">"ISO B0"</string>
+ <string name="mediasize_iso_b1" msgid="6072859628278739957">"ISO B1"</string>
+ <string name="mediasize_iso_b2" msgid="1348731852150380378">"ISO B2"</string>
+ <string name="mediasize_iso_b3" msgid="2612510181259261379">"ISO B3"</string>
+ <string name="mediasize_iso_b4" msgid="695151378838115434">"ISO B4"</string>
+ <string name="mediasize_iso_b5" msgid="4863754285582212487">"ISO B5"</string>
+ <string name="mediasize_iso_b6" msgid="5305816292139647241">"ISO B6"</string>
+ <string name="mediasize_iso_b7" msgid="531673542602786624">"ISO B7"</string>
+ <string name="mediasize_iso_b8" msgid="9164474595708850034">"ISO B8"</string>
+ <string name="mediasize_iso_b9" msgid="282102976764774160">"ISO B9"</string>
+ <string name="mediasize_iso_b10" msgid="4517141714407898976">"ISO B10"</string>
+ <string name="mediasize_iso_c0" msgid="3103521357901591100">"ISO C0"</string>
+ <string name="mediasize_iso_c1" msgid="1231954105985048595">"ISO C1"</string>
+ <string name="mediasize_iso_c2" msgid="927702816980087462">"ISO C2"</string>
+ <string name="mediasize_iso_c3" msgid="835154173518304159">"ISO C3"</string>
+ <string name="mediasize_iso_c4" msgid="5095951985108194011">"ISO C4"</string>
+ <string name="mediasize_iso_c5" msgid="1985397450332305739">"ISO C5"</string>
+ <string name="mediasize_iso_c6" msgid="8147421924174693013">"ISO C6"</string>
+ <string name="mediasize_iso_c7" msgid="8993994925276122950">"ISO C7"</string>
+ <string name="mediasize_iso_c8" msgid="6871178104139598957">"ISO C8"</string>
+ <string name="mediasize_iso_c9" msgid="7983532635227561362">"ISO C9"</string>
+ <string name="mediasize_iso_c10" msgid="5040764293406765584">"ISO C10"</string>
+ <string name="mediasize_na_letter" msgid="2841414839888344296">"লেটাৰ"</string>
+ <string name="mediasize_na_gvrnmt_letter" msgid="5295836838862962809">"চৰকাৰী পত্ৰ"</string>
+ <string name="mediasize_na_legal" msgid="8621364037680465666">"লিগেল"</string>
+ <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"জুনিয়ৰ লিগেল"</string>
+ <string name="mediasize_na_ledger" msgid="5567030340509075333">"লেজাৰ"</string>
+ <string name="mediasize_na_tabloid" msgid="4571735038501661757">"টে\'বলইড"</string>
+ <string name="mediasize_na_index_3x5" msgid="5182901917818625126">"ইনডেক্স কাৰ্ড ৩x৫"</string>
+ <string name="mediasize_na_index_4x6" msgid="7687620625422312396">"ইনডেক্স কাৰ্ড ৪x৬"</string>
+ <string name="mediasize_na_index_5x8" msgid="8834215284646872800">"ইনডেক্স কাৰ্ড ৫x৮"</string>
+ <string name="mediasize_na_monarch" msgid="213639906956550754">"ম\'নাৰ্ক"</string>
+ <string name="mediasize_na_quarto" msgid="835778493593023223">"কুৱাট্ৰো"</string>
+ <string name="mediasize_na_foolscap" msgid="1573911237983677138">"ফুলস্কেপ"</string>
+ <string name="mediasize_chinese_roc_8k" msgid="3626855847189438896">"ROC 8K"</string>
+ <string name="mediasize_chinese_roc_16k" msgid="9182191577022943355">"ROC 16K"</string>
+ <string name="mediasize_chinese_prc_1" msgid="4793232644980170500">"PRC 1"</string>
+ <string name="mediasize_chinese_prc_2" msgid="5404109730975720670">"PRC 2"</string>
+ <string name="mediasize_chinese_prc_3" msgid="1335092253339363526">"PRC 3"</string>
+ <string name="mediasize_chinese_prc_4" msgid="9167997800486569834">"PRC 4"</string>
+ <string name="mediasize_chinese_prc_5" msgid="845875168823541497">"PRC 5"</string>
+ <string name="mediasize_chinese_prc_6" msgid="3220325667692648789">"PRC 6"</string>
+ <string name="mediasize_chinese_prc_7" msgid="1776792138507038527">"PRC 7"</string>
+ <string name="mediasize_chinese_prc_8" msgid="1417176642687456692">"PRC 8"</string>
+ <string name="mediasize_chinese_prc_9" msgid="4785983473123798365">"PRC 9"</string>
+ <string name="mediasize_chinese_prc_10" msgid="7847982299391851899">"PRC 10"</string>
+ <string name="mediasize_chinese_prc_16k" msgid="262793383539980677">"PRC 16K"</string>
+ <string name="mediasize_chinese_om_pa_kai" msgid="5256815579447959814">"Pa Kai"</string>
+ <string name="mediasize_chinese_om_dai_pa_kai" msgid="7336412963441354407">"Dai Pa Kai"</string>
+ <string name="mediasize_chinese_om_jurro_ku_kai" msgid="6324465444100490742">"Jurro Ku Kai"</string>
+ <string name="mediasize_japanese_jis_b10" msgid="1787262845627694376">"JIS B10"</string>
+ <string name="mediasize_japanese_jis_b9" msgid="3336035783663287470">"JIS B9"</string>
+ <string name="mediasize_japanese_jis_b8" msgid="6195398299104345731">"JIS B8"</string>
+ <string name="mediasize_japanese_jis_b7" msgid="1674621886902828884">"JIS B7"</string>
+ <string name="mediasize_japanese_jis_b6" msgid="4170576286062657435">"JIS B6"</string>
+ <string name="mediasize_japanese_jis_b5" msgid="4899297958100032533">"JIS B5"</string>
+ <string name="mediasize_japanese_jis_b4" msgid="4213158129126666847">"JIS B4"</string>
+ <string name="mediasize_japanese_jis_b3" msgid="8513715307410310696">"JIS B3"</string>
+ <string name="mediasize_japanese_jis_b2" msgid="4777690211897131190">"JIS B2"</string>
+ <string name="mediasize_japanese_jis_b1" msgid="4608142385457034603">"JIS B1"</string>
+ <string name="mediasize_japanese_jis_b0" msgid="7587108366572243991">"JIS B0"</string>
+ <string name="mediasize_japanese_jis_exec" msgid="5244075432263649068">"JIS Exec"</string>
+ <string name="mediasize_japanese_chou4" msgid="4941652015032631361">"Chou4"</string>
+ <string name="mediasize_japanese_chou3" msgid="6387319169263957010">"Chou3"</string>
+ <string name="mediasize_japanese_chou2" msgid="1299112025415343982">"Chou2"</string>
+ <string name="mediasize_japanese_hagaki" msgid="8070115620644254565">"Hagaki"</string>
+ <string name="mediasize_japanese_oufuku" msgid="6049065587307896564">"Oufuku"</string>
+ <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
+ <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
+ <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
+ <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"অজ্ঞাত প\'ৰ্ট্ৰেইট"</string>
+ <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"অজ্ঞাত লেণ্ডস্কেইপ"</string>
+ <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"বাতিল কৰা হ\'ল"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"সমল লিখাত আসোঁৱাহ"</string>
+ <string name="reason_unknown" msgid="6048913880184628119">"অজ্ঞাত"</string>
+ <string name="reason_service_unavailable" msgid="7824008732243903268">"প্ৰিণ্টিং সেৱা সক্ষম নহয়"</string>
+ <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> সেৱা ইনষ্টল কৰা হ\'ল"</string>
+ <string name="print_service_installed_message" msgid="5897362931070459152">"সক্ষম কৰিবলৈ টিপক"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="8641662909467236832">"প্ৰশাসকৰ পিন দিয়ক"</string>
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"পিন দিয়ক"</string>
+ <string name="restr_pin_incorrect" msgid="8571512003955077924">"অশুদ্ধ"</string>
+ <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"বৰ্তমানৰ পিন"</string>
+ <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"নতুন পিন"</string>
+ <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"নতুন পিন নিশ্চিত কৰক"</string>
+ <string name="restr_pin_create_pin" msgid="8017600000263450337">"সীমাবদ্ধতা সংশোধন কৰিবলৈ এটা পিন সৃষ্টি কৰক"</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"পিনবোৰ মিলা নাই। আকৌ চেষ্টা কৰক।"</string>
+ <string name="restr_pin_error_too_short" msgid="8173982756265777792">"পিনটো অতি চুটি। কমেও ৪টা সংখ্যাৰ হ\'ব লাগিব।"</string>
+ <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+ <item quantity="one"> <xliff:g id="COUNT">%d</xliff:g> ছেকেণ্ডত আকৌ চেষ্টা কৰক</item>
+ <item quantity="other"> <xliff:g id="COUNT">%d</xliff:g> ছেকেণ্ডত আকৌ চেষ্টা কৰক</item>
+ </plurals>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"পিছত আকৌ চেষ্টা কৰক"</string>
+ <!-- no translation found for immersive_cling_title (8394201622932303336) -->
+ <skip />
+ <!-- no translation found for immersive_cling_description (3482371193207536040) -->
+ <skip />
+ <!-- no translation found for immersive_cling_positive (5016839404568297683) -->
+ <skip />
+ <string name="done_label" msgid="2093726099505892398">"সম্পন্ন কৰা হ\'ল"</string>
+ <string name="hour_picker_description" msgid="6698199186859736512">"ঘড়ীৰ বৃত্তাকাৰ শ্লাইডাৰ"</string>
+ <string name="minute_picker_description" msgid="8606010966873791190">"মিনিটৰ বৃত্তাকাৰ শ্লাইডাৰ"</string>
+ <string name="select_hours" msgid="6043079511766008245">"ঘণ্টা বাছনি কৰক"</string>
+ <string name="select_minutes" msgid="3974345615920336087">"মিনিট বাছনি কৰক"</string>
+ <string name="select_day" msgid="7774759604701773332">"মাহ আৰু দিন বাছনি কৰক"</string>
+ <string name="select_year" msgid="7952052866994196170">"বছৰ বাছনি কৰক"</string>
+ <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> মচা হ\'ল"</string>
+ <string name="managed_profile_label_badge" msgid="2355652472854327647">"কৰ্মস্থান <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"২য় কার্য <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"৩য় কার্য <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন কৰাৰ পূৰ্বে পিন দিবলৈ কওক"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"আনপিন কৰাৰ পূৰ্বে আনলক আৰ্হি দিবলৈ কওক"</string>
+ <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"আনপিন কৰাৰ পূৰ্বে পাছৱৰ্ড দিবলৈ কওক"</string>
+ <string name="package_installed_device_owner" msgid="6875717669960212648">"আপোনাৰ প্ৰশাসকে ইনষ্টল কৰিছে"</string>
+ <string name="package_updated_device_owner" msgid="1847154566357862089">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
+ <string name="package_deleted_device_owner" msgid="2307122077550236438">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
+ <string name="battery_saver_description" msgid="5394663545060026162">"বেটাৰিৰ অৱস্থা উন্নত কৰাত সহায় কৰিবলৈ বেটাৰি সঞ্চয়কাৰী সুবিধাই আপোনাৰ ডিভাইচৰ কাৰ্যদক্ষতা হ্ৰাস কৰে আৰু কম্পন, অৱস্থান সেৱা আৰু অধিকাংশ নেপথ্য ডেটা সীমিত কৰে। ছিংকৰ ওপৰত নির্ভৰশীল ইমেইল, মেছেজিং আৰু অন্য এপসমূহ আপুনি নোখোলা পৰ্যন্ত আপডেট নহ\'বও পাৰে।\n\nআপোনাৰ ডিভাইচ চ্চার্জ কৰি থকাৰ সময়ত বেটাৰি সঞ্চয়কাৰী সুবিধা স্বয়ংক্ৰিয়ভাৱে অফ হ\'ব।"</string>
+ <string name="data_saver_description" msgid="6015391409098303235">"ডেটা ব্য়ৱহাৰ মাত্ৰা কম কৰিবৰ বাবে ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা ব্য়ৱহাৰ কৰিব পাৰে, কিন্তু সঘনাই এই কার্য কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ এইয়ে হ\'ব পাৰে যে, উদাহৰণস্বৰূপে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ\'ব।"</string>
+ <string name="data_saver_enable_title" msgid="4674073932722787417">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string>
+ <string name="data_saver_enable_button" msgid="7147735965247211818">"অন কৰক"</string>
+ <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+ <item quantity="one"> %1$d মিনিটৰ বাবে (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পৰ্যন্ত)</item>
+ <item quantity="other"> %1$d মিনিটৰ বাবে (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পৰ্যন্ত)</item>
+ </plurals>
+ <!-- no translation found for zen_mode_duration_minutes_summary_short (6830154222366042597) -->
+ <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+ <item quantity="one">%1$d ঘণ্টাৰ বাবে (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পৰ্যন্ত)</item>
+ <item quantity="other">%1$d ঘণ্টাৰ বাবে (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পৰ্যন্ত)</item>
+ </plurals>
+ <!-- no translation found for zen_mode_duration_hours_summary_short (4787552595253082371) -->
+ <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+ <item quantity="one">%d মিনিটৰ বাবে</item>
+ <item quantity="other">%d মিনিটৰ বাবে</item>
+ </plurals>
+ <!-- no translation found for zen_mode_duration_minutes_short (2199350154433426128) -->
+ <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+ <item quantity="one">%d ঘণ্টাৰ বাবে</item>
+ <item quantity="other">%d ঘণ্টাৰ বাবে</item>
+ </plurals>
+ <!-- no translation found for zen_mode_duration_hours_short (6748277774662434217) -->
+ <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পৰ্যন্ত"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (পৰৱৰ্তী এলার্ম) পর্যন্ত"</string>
+ <!-- no translation found for zen_mode_forever (931849471004038757) -->
+ <skip />
+ <!-- no translation found for zen_mode_forever_dnd (3792132696572189081) -->
+ <skip />
+ <!-- no translation found for zen_mode_rule_name_combination (191109939968076477) -->
+ <skip />
+ <string name="toolbar_collapse_description" msgid="2821479483960330739">"সংকুচিত কৰক"</string>
+ <!-- no translation found for zen_mode_feature_name (5254089399895895004) -->
+ <skip />
+ <!-- no translation found for zen_mode_downtime_feature_name (2626974636779860146) -->
+ <skip />
+ <!-- no translation found for zen_mode_default_weeknights_name (3081318299464998143) -->
+ <skip />
+ <!-- no translation found for zen_mode_default_weekends_name (2786495801019345244) -->
+ <skip />
+ <!-- no translation found for zen_mode_default_events_name (8158334939013085363) -->
+ <skip />
+ <string name="zen_mode_default_every_night_name" msgid="3012363838882944175">"নিদ্ৰাৰত"</string>
+ <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g>ৰ দ্বাৰা মিউট কৰা হৈছে"</string>
+ <string name="system_error_wipe_data" msgid="6608165524785354962">"আপোনাৰ ডিভাইচত এটা আভ্যন্তৰীণ সমস্যা আছে আৰু আপুনি ফেক্টৰী ডেটা ৰিছেট নকৰালৈকে ই সুস্থিৰভাৱে কাম নকৰিব পাৰে।"</string>
+ <string name="system_error_manufacturer" msgid="8086872414744210668">"আপোনাৰ ডিভাইচত এটা আভ্যন্তৰীণ সমস্যা আছে। সবিশেষ জানিবৰ বাবে আপোনাৰ ডিভাইচ নির্মাতাৰ সৈতে যোগাযোগ কৰক।"</string>
+ <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD অনুৰোধক DIAL অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD অনুৰোধক SS অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD অনুৰোধক নতুন USSD অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ussd_to_dial_video" msgid="585340552561515305">"USSD অনুৰোধক ভিডিঅ\' DIAL অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS অনুৰোধক DIAL অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ss_to_dial_video" msgid="4306210904450719045">"SS অনুৰোধক ভিডিঅ\' DIAL অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS অনুৰোধক USSD অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS অনুৰোধক নতুন SS অনুৰোধলৈ সংশোধিত কৰা হৈছে।"</string>
+ <string name="notification_work_profile_content_description" msgid="4600554564103770764">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
+ <string name="expand_button_content_description_collapsed" msgid="3609784019345534652">"বিস্তাৰ কৰক"</string>
+ <string name="expand_button_content_description_expanded" msgid="8520652707158554895">"সংকুচিত কৰক"</string>
+ <string name="expand_action_accessibility" msgid="5307730695723718254">"সম্প্ৰসাৰণ ট’গল কৰক"</string>
+ <!-- no translation found for usb_midi_peripheral_name (7221113987741003817) -->
+ <skip />
+ <!-- no translation found for usb_midi_peripheral_manufacturer_name (7176526170008970168) -->
+ <skip />
+ <!-- no translation found for usb_midi_peripheral_product_name (4971827859165280403) -->
+ <skip />
+ <!-- no translation found for floating_toolbar_open_overflow_description (4797287862999444631) -->
+ <skip />
+ <!-- no translation found for floating_toolbar_close_overflow_description (559796923090723804) -->
+ <skip />
+ <string name="maximize_button_text" msgid="7543285286182446254">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string>
+ <string name="close_button_text" msgid="3937902162644062866">"বন্ধ কৰক"</string>
+ <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
+ <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বাছনি কৰা হ\'ল</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বাছনি কৰা হ\'ল</item>
+ </plurals>
+ <string name="default_notification_channel_label" msgid="5929663562028088222">"শ্ৰেণীবদ্ধ নকৰা"</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"এই জাননীবোৰৰ গুৰুত্ব আপুনি ছেট কৰব লাগিব।"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"এই কার্যৰ সৈতে জড়িত থকা লোকসকলক ভিত্তি কৰি এইয়া গুৰুত্বপূর্ণ বুলি বিবেচনা কৰা হৈছ।"</string>
+ <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে নতুন ব্য়ৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউন্টৰ এজন ব্য়ৱহাৰকাৰী ইতিমধ্য়ে আছে) জৰিয়তে নতুন ব্য়ৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"ভাষা এটা যোগ কৰক"</string>
+ <string name="country_selection_title" msgid="2954859441620215513">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
+ <string name="search_language_hint" msgid="7042102592055108574">"ভাষাৰ নাম লিখক"</string>
+ <string name="language_picker_section_suggested" msgid="8414489646861640885">"প্ৰস্তাৱিত"</string>
+ <string name="language_picker_section_all" msgid="3097279199511617537">"সকলো ভাষা"</string>
+ <string name="region_picker_section_all" msgid="8966316787153001779">"সকলো অঞ্চল"</string>
+ <string name="locale_search_menu" msgid="2560710726687249178">"অনুসন্ধান কৰক"</string>
+ <!-- no translation found for work_mode_off_title (1118691887588435530) -->
+ <skip />
+ <!-- no translation found for work_mode_off_message (5130856710614337649) -->
+ <skip />
+ <string name="work_mode_turn_on" msgid="2062544985670564875">"অন কৰক"</string>
+ <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
+ <skip />
+ <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
+ <skip />
+ <string name="new_sms_notification_title" msgid="8442817549127555977">"আপুনি নতুন বার্তা লাভ কৰিছে"</string>
+ <string name="new_sms_notification_content" msgid="7002938807812083463">"চাবলৈ এছএমএছ এপ্ খোলক"</string>
+ <string name="user_encrypted_title" msgid="9054897468831672082">"কিছুমান কৰ্মক্ষমতা সীমিত হ\'ব পাৰে"</string>
+ <string name="user_encrypted_message" msgid="4923292604515744267">"আনলক কৰিবলৈ টিপক"</string>
+ <string name="user_encrypted_detail" msgid="5708447464349420392">"ব্য়ৱহাৰকাৰীৰ ডেটা লক হৈ আছে"</string>
+ <string name="profile_encrypted_detail" msgid="3700965619978314974">"কৰ্মস্থানৰ প্ৰ’ফাইল লক হৈ আছে"</string>
+ <string name="profile_encrypted_message" msgid="6964994232310195874">"কৰ্মস্থানৰ প্ৰ’ফাইল আনলক কৰিবলৈ টিপক"</string>
+ <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>ৰ সৈতে সংযুক্ত হৈ আছে"</string>
+ <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ফাইলসমূহ চাবৰ বাবে টিপক"</string>
+ <string name="pin_target" msgid="3052256031352291362">"পিন"</string>
+ <string name="unpin_target" msgid="3556545602439143442">"আনপিন"</string>
+ <string name="app_info" msgid="6856026610594615344">"এপ্ সম্পৰ্কীয় তথ্য"</string>
+ <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="demo_starting_message" msgid="5268556852031489931">"ডেম\' আৰম্ভ কৰি থকা হৈছে…"</string>
+ <string name="demo_restarting_message" msgid="952118052531642451">"ডিভাইচটো আকৌ ছেটিং কৰি থকা হৈছে…"</string>
+ <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>ক অক্ষম কৰা হ\'ল"</string>
+ <string name="conference_call" msgid="3751093130790472426">"কনফাৰেঞ্চ কল"</string>
+ <string name="tooltip_popup_title" msgid="5253721848739260181">"টুলটিপ"</string>
+ <string name="app_category_game" msgid="5431836943981492993">"গেম"</string>
+ <string name="app_category_audio" msgid="1659853108734301647">"সংগীত আৰু ধ্বনি"</string>
+ <string name="app_category_video" msgid="2728726078629384196">"চলচ্চিত্ৰ আৰু ভিডিঅ\'"</string>
+ <string name="app_category_image" msgid="4867854544519846048">"ফট\' আৰু প্ৰতিচ্ছবি"</string>
+ <string name="app_category_social" msgid="5842783057834965912">"সামাজিক আৰু যোগাযোগ"</string>
+ <string name="app_category_news" msgid="7496506240743986873">"বাতৰি আৰু আলোচনী"</string>
+ <string name="app_category_maps" msgid="5878491404538024367">"মেপ আৰু দিক্-নিৰ্দেশনা"</string>
+ <string name="app_category_productivity" msgid="3742083261781538852">"উৎপাদনশীলতা"</string>
+ <string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ডিভাইচৰ সঞ্চয়াগাৰ"</string>
+ <string name="adb_debugging_notification_channel_tv" msgid="5537766997350092316">"ইউএছবি ডিবাগিং"</string>
+ <string name="time_picker_hour_label" msgid="2979075098868106450">"ঘণ্টা"</string>
+ <string name="time_picker_minute_label" msgid="5168864173796598399">"মিনিট"</string>
+ <string name="time_picker_header_text" msgid="143536825321922567">"সময় ছেট কৰক"</string>
+ <string name="time_picker_input_error" msgid="7574999942502513765">"এটা মান্য সময় দিয়ক"</string>
+ <string name="time_picker_prompt_label" msgid="7588093983899966783">"সময় টাইপ কৰক"</string>
+ <string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"সময়ৰ ইনপুটৰ বাবে পাঠৰ ইনপুট ম\'ডলৈ যাওক।"</string>
+ <string name="time_picker_radial_mode_description" msgid="4953403779779557198">"সময়ৰ ইনপুটৰ বাবে ঘড়ী ম\'ডলৈ যাওক।"</string>
+ <string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"স্বয়ংপূৰ্তিৰ বিকল্পসমূহ"</string>
+ <string name="autofill_save_accessibility_title" msgid="7244365268417107822">"পিছত স্বয়ংপূৰ্তি কৰিবলৈ ছেভ কৰক"</string>
+ <string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"সমলসমূহ স্বয়ংপূৰ্তি কৰিব নোৱাৰি"</string>
+ <string name="autofill_picker_no_suggestions" msgid="3908514303773350735">"কোনো স্বয়ংপূৰ্তি পৰামৰ্শ নাই"</string>
+ <plurals name="autofill_picker_some_suggestions" formatted="false" msgid="5506565809835815274">
+ <item quantity="one"><xliff:g id="COUNT">%1$s</xliff:g>টা স্বয়ংপূৰ্তি পৰামৰ্শ</item>
+ <item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g>টা স্বয়ংপূৰ্তি পৰামৰ্শ</item>
+ </plurals>
+ <string name="autofill_save_title" msgid="3345527308992082601">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>ত ছেভ কৰিবনে?"</string>
+ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g>ক <b><xliff:g id="LABEL">%2$s</xliff:g></b>ত ছেভ কৰিবনে?"</string>
+ <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> আৰু <xliff:g id="TYPE_1">%2$s</xliff:g>ক <b><xliff:g id="LABEL">%3$s</xliff:g></b>ত ছেভ কৰিবনে?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<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>ক <b><xliff:g id="LABEL">%4$s</xliff:g></b>ত ছেভ কৰিবনে?"</string>
+ <string name="autofill_save_yes" msgid="6398026094049005921">"ছেভ কৰক"</string>
+ <string name="autofill_save_no" msgid="2625132258725581787">"নালাগে, ধন্যবাদ"</string>
+ <string name="autofill_save_type_password" msgid="5288448918465971568">"পাছৱৰ্ড"</string>
+ <string name="autofill_save_type_address" msgid="4936707762193009542">"ঠিকনা"</string>
+ <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ক্ৰেডিট কাৰ্ড"</string>
+ <string name="autofill_save_type_username" msgid="239040540379769562">"ব্যৱহাৰকাৰীৰ নাম"</string>
+ <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ইমেইল ঠিকনা"</string>
+ <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"শান্ত হৈ থাকক আৰু ওচৰৰ ক\'ৰবাত আশ্ৰয় বিচাৰক।"</string>
+ <string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"উপকূলীয় আৰু নদী-কাযৰীয়া অঞ্চলৰ পৰা তৎক্ষণাৎ আঁতৰ হওক আৰু ওখ অঞ্চলৰ নিচিনা নিৰাপদ ঠাইত আশ্ৰয় লওক।"</string>
+ <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"শান্ত হৈ থাকক আৰু ওচৰৰ ক\'ৰবাত আশ্ৰয় বিচাৰক।"</string>
+ <string name="etws_primary_default_message_test" msgid="2709597093560037455">"জৰুৰীকালীন বাৰ্তা সম্পৰ্কীয় পৰীক্ষণ"</string>
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"উত্তৰ দিয়ক"</string>
+ <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"ভইচৰ বাবে ছিম ব্যৱহাৰৰ অনুমতি নাই"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"ভইচৰ বাবে ছিমৰ প্ৰ\'ভিজন কৰা হোৱা নাই"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"ভইচৰ বাবে ছিম ব্যৱহাৰৰ অনুমতি নাই"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"ভইচৰ বাবে ফ\'ন ব্যৱহাৰৰ অনুমতি নাই"</string>
+ <string name="popup_window_default_title" msgid="4874318849712115433">"পপআপ ৱিণ্ড\'"</string>
+ <string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+ <!-- no translation found for shortcut_restored_on_lower_version (4860853725206702336) -->
+ <skip />
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"এপটোত বেকআপ আৰু পুনঃস্থাপন সুবিধা নথকাৰ বাবে শ্বৰ্টকাট পুনঃস্থাপন কৰিবপৰা নগ\'ল"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"এপৰ স্বাক্ষৰৰ অমিল হোৱাৰ বাবে শ্বৰ্টকাট পুনঃস্থাপন কৰিবপৰা নগ\'ল"</string>
+ <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"শ্বৰ্টকাট পুনঃস্থাপন কৰিবপৰা নগ\'ল"</string>
+ <string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"শ্বৰ্টকাট অক্ষম কৰি থোৱা হৈছে"</string>
+ <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
+ <skip />
+ <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
+ <skip />
+ <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
+ <skip />
+ <!-- no translation found for slices_permission_request (8484943441501672932) -->
+ <skip />
+ <!-- no translation found for screenshot_edit (7867478911006447565) -->
+ <skip />
+ <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
+ <skip />
+ <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
+ <skip />
+ <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
+ <skip />
+</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 082a7a6..bd3de48 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -185,7 +185,7 @@
<string name="network_logging_notification_title" msgid="6399790108123704477">"Прылада знаходзіцца пад кіраваннем"</string>
<string name="network_logging_notification_text" msgid="7930089249949354026">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Даныя вашай прылады будуць сцерты"</string>
- <string name="factory_reset_message" msgid="7972496262232832457">"Немагчыма выкарыстоўваць праграму адміністратара. Зараз звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара вашай арганізацыі."</string>
+ <string name="factory_reset_message" msgid="9024647691106150160">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string>
<string name="printing_disabled_by" msgid="8936832919072486965">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Параметры планшэта"</string>
@@ -242,6 +242,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Рэжым палёту"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Уключаны рэжым \"У самалёце\""</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Рэжым \"У самалёце\" адключаны"</string>
+ <string name="global_action_toggle_battery_saver" msgid="708515500418994208">"Эканомія зараду"</string>
+ <string name="global_action_battery_saver_on_status" msgid="484059130698197787">"Рэжым эканоміі зараду выключаны"</string>
+ <string name="global_action_battery_saver_off_status" msgid="75550964969478405">"Рэжым эканоміі зараду ўключаны"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Налады"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Дапамога"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Галас. дапамога"</string>
@@ -311,7 +314,7 @@
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Выконваць жэсты"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Можна кранаць, праводзіць пальцам, маштабаваць шчыпком, а таксама выконваць іншыя жэсты."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Жэсты адбіткаў пальцаў"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Можа распазнаваць жэсты на сканеры адбіткаў пальцаў прылады."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Можа распазнаваць жэсты на сканеры адбіткаў пальцаў прылады."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"адключаць ці змяняць радок стану"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"быць панэллю стану"</string>
@@ -362,6 +365,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Дазваляе прыкладанню захоўваць некаторыя пастаянныя часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых прыкладанняў, i запаволiць працу планшэта."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Дазваляе праграме пастаянна захоўваць некаторыя свае часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых праграм, i запаволiць працу тэлевізара."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Дазваляе прыкладанню захоўваць некаторыя пастаянныя часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых прыкладанняў, i запаволiць працу тэлефона."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"запусціць асноўныя сэрвісы"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Дазваляе праграме выкарыстоўваць асноўныя сэрвісы."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"вымерыць прастору для захоўвання прыкладання"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дазваляе прыкладанням атрымліваць яго код, дадзеныя і аб\'ём кэш-памяці"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"змена сістэмных налад"</string>
@@ -808,6 +813,8 @@
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Узор разблакiроўкі."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фэйскантроль"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-код разблакiроўкі."</string>
+ <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Разблакіроўка SIM-карты з дапамогай PIN-кода."</string>
+ <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Разблакіроўка SIM-карты з дапамогай PUK-кода."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Пароль разблакiроўкі."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Вобласць узора."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Вобласць слайда."</string>
@@ -1114,29 +1121,33 @@
<string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Праверыць на наяўнасць абнаўленняў"</string>
<string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> парушыў уласную палітыку StrictMode."</string>
- <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
- <string name="android_start_title" msgid="8418054686415318207">"Android запускаецца..."</string>
+ <!-- no translation found for android_upgrading_title (7513829952443484438) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (4503169817302593560) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (7009520271220804517) -->
+ <skip />
+ <!-- no translation found for android_start_title (4536778526365907780) -->
+ <skip />
+ <!-- no translation found for android_start_title (4929837533850340472) -->
+ <skip />
+ <!-- no translation found for android_start_title (7467484093260449437) -->
+ <skip />
<string name="android_upgrading_fstrim" msgid="8036718871534640010">"Аптымізацыя сховішча."</string>
- <string name="android_upgrading_notification_title" msgid="8428357096969413169">"Абнаўленне Android завяршаецца…"</string>
- <string name="android_upgrading_notification_body" msgid="5761201379457064286">"Пэўныя праграмы могуць не працаваць належным чынам, пакуль не скончыцца абнаўленне"</string>
+ <!-- no translation found for android_upgrading_notification_title (1511552415039349062) -->
+ <skip />
<string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> абнаўляецца…"</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"Аптымізацыя прыкладання <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="android_preparing_apk" msgid="8162599310274079154">"Падрыхтоўка <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Завяршэнне загрузкі."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Прыкладанне \"<xliff:g id="APP">%1$s</xliff:g>\" запушчанае"</string>
- <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
- <skip />
- <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
- <skip />
- <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
- <skip />
- <!-- no translation found for old_app_action (3044685170829526403) -->
- <skip />
- <!-- no translation found for new_app_action (6694851182870774403) -->
- <skip />
- <!-- no translation found for new_app_description (5894852887817332322) -->
- <skip />
+ <string name="heavy_weight_notification_detail" msgid="2304833848484424985">"Націсніце, каб вярнуцца да гульні"</string>
+ <string name="heavy_weight_switcher_title" msgid="387882830435195342">"Выберыце гульню"</string>
+ <string name="heavy_weight_switcher_text" msgid="4176781660362912010">"Для больш прадукцыйнай працы прылады адначасова дазваляецца адкрыць толькі адну з гэтых гульняў."</string>
+ <string name="old_app_action" msgid="3044685170829526403">"Вярнуцца да праграмы \"<xliff:g id="OLD_APP">%1$s</xliff:g>\""</string>
+ <string name="new_app_action" msgid="6694851182870774403">"Адкрыць праграму \"<xliff:g id="NEW_APP">%1$s</xliff:g>\""</string>
+ <string name="new_app_description" msgid="5894852887817332322">"Праграма \"<xliff:g id="OLD_APP">%1$s</xliff:g>\" будзе закрыта. Даныя не будуць захаваны"</string>
<string name="dump_heap_notification" msgid="2618183274836056542">"Працэс <xliff:g id="PROC">%1$s</xliff:g> перавысіў ліміт памяці"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"Быў сабраны дамп кучы; дакраніцеся, каб абагуліць"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Абагуліць дамп дынамічнай вобласці?"</string>
@@ -1182,7 +1193,8 @@
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Не атрымалася падключыцца да адкрытай сеткі Wi‑Fi"</string>
<string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Дакраніцеся, каб убачыць усе сеткі"</string>
<string name="wifi_available_action_connect" msgid="2635699628459488788">"Падключыцца"</string>
- <string name="wifi_available_action_all_networks" msgid="1100098935861622985">"Усе сеткі"</string>
+ <!-- no translation found for wifi_available_action_all_networks (4368435796357931006) -->
+ <skip />
<string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi уключыцца аўтаматычна"</string>
<string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Побач з захаванай сеткай з высакаякасным сігналам"</string>
<string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Не ўключаць зноў"</string>
@@ -1248,6 +1260,7 @@
<string name="sim_restart_button" msgid="4722407842815232347">"Перазапусціць"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Уключыць мабільную сувязь"</string>
<string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Спампаваць праграму аператара для актывацыі новай SIM-карты"</string>
+ <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"Для актывацыі новай SIM-карты спампуйце праграму <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Спампаваць праграму"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Устаўлена новая SIM-карта"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Краніце, каб наладзіць"</string>
@@ -1291,7 +1304,7 @@
<string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> паказваецца паверх іншых праграм"</string>
<string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> паказв. паверх іншых праграм"</string>
<string name="alert_windows_notification_message" msgid="8917232109522912560">"Калі вы не хочаце, каб праграма <xliff:g id="NAME">%s</xliff:g> выкарыстоўвала гэту функцыю, дакраніцеся, каб адкрыць налады і адключыць гэта."</string>
- <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"АДКЛЮЧЫЦЬ"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="2902891971380544651">"Выключыць"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1464,22 +1477,19 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
- <string name="data_usage_warning_title" msgid="3620440638180218181">"Абвестка аб выкарыстанні трафіка"</string>
- <string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string>
- <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
- <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
+ <string name="data_usage_warning_title" msgid="6499834033204801605">"Папярэджанне аб перавышэнні ліміту трафіка"</string>
+ <string name="data_usage_warning_body" msgid="7340198905103751676">"Вы выкарысталі <xliff:g id="APP">%s</xliff:g> даных"</string>
<string name="data_usage_mobile_limit_title" msgid="6561099244084267376">"Дасягн. ліміт маб. перад. даных"</string>
<string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Дасягн. ліміт перад. даных Wi-Fi"</string>
- <string name="data_usage_limit_body" msgid="291731708279614081">"Перад.даных спын. да канца цыкла"</string>
- <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Перавышаны ліміт 2G-3G"</string>
- <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Перавышаны ліміт дадзеных 4G"</string>
- <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Перавышаны ліміт мабільных дадзеных"</string>
- <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Перав. ліміт па дадзеным Wi-Fi"</string>
- <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Аб\'ём <xliff:g id="SIZE">%s</xliff:g> перавышае устаноўл. мяжу."</string>
+ <string name="data_usage_limit_body" msgid="2908179506560812973">"Выкарыстанне даных прыпынена да канца цыкла"</string>
+ <string name="data_usage_mobile_limit_snoozed_title" msgid="3171402244827034372">"Перавышаны ліміт мабільных даных"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="3547771791046344188">"Перавышаны ліміт трафіка Wi-Fi"</string>
+ <string name="data_usage_limit_snoozed_body" msgid="1671222777207603301">"Вы перавысілі ліміт на <xliff:g id="SIZE">%s</xliff:g>"</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Зыходныя дадзеныя абмежаваныя"</string>
<string name="data_usage_restricted_body" msgid="469866376337242726">"Дакраніцеся, каб зняць абмежав."</string>
- <string name="data_usage_rapid_title" msgid="4579994056245665351">"Значнае выкарыстанне трафіка"</string>
- <string name="data_usage_rapid_body" msgid="4899922842674185567">"У апошнія некалькі дзён вы выкарысталі больш трафіку, чым звычайна. Націсніце для прагляду выкарыстання і налад."</string>
+ <string name="data_usage_rapid_title" msgid="1809795402975261331">"Інтэнсіўнае выкарыстанне трафіка"</string>
+ <string name="data_usage_rapid_body" msgid="6897825788682442715">"Праграмы выкарысталі больш даных, чым звычайна"</string>
+ <string name="data_usage_rapid_app_body" msgid="5396680996784142544">"У праграме <xliff:g id="APP">%s</xliff:g> было выкарыстана больш даных, чым звычайна"</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Сертыфікат бяспекі"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Гэты сертыфікат сапраўдны."</string>
<string name="issued_to" msgid="454239480274921032">"Каму выдадзена:"</string>
diff --git a/core/res/res/values-mcc001-mnc01-as/strings.xml b/core/res/res/values-mcc001-mnc01-as/strings.xml
new file mode 100644
index 0000000..93b8fc7
--- /dev/null
+++ b/core/res/res/values-mcc001-mnc01-as/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me" msgid="2238090225563073546">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370-as/strings.xml b/core/res/res/values-mcc302-mnc370-as/strings.xml
new file mode 100644
index 0000000..c0ad316
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"%s"</item>
+ <item msgid="8117276330682171665">"%s ৱাই-ফাই"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-as/strings.xml b/core/res/res/values-mcc302-mnc720-as/strings.xml
new file mode 100644
index 0000000..0ab4dac
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"%s"</item>
+ <item msgid="5094669985484060934">"%s ৱাই-ফাই"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc030-as/strings.xml b/core/res/res/values-mcc310-mnc030-as/strings.xml
new file mode 100644
index 0000000..27953b8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc030-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1930079814544869756">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="2995576894416087107">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc150-as/strings.xml b/core/res/res/values-mcc310-mnc150-as/strings.xml
new file mode 100644
index 0000000..174cfe3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc150-as/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me" msgid="5207603948149789531">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc170-as/strings.xml b/core/res/res/values-mcc310-mnc170-as/strings.xml
new file mode 100644
index 0000000..37b727b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc170-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1130721094178658338">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="3173546391131606065">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc280-as/strings.xml b/core/res/res/values-mcc310-mnc280-as/strings.xml
new file mode 100644
index 0000000..3bc3c1f
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc280-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="5562215652599183258">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="822496463303720579">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc380-as/strings.xml b/core/res/res/values-mcc310-mnc380-as/strings.xml
new file mode 100644
index 0000000..4c4a705
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc380-as/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="6367773216941648568">"ছিমৰ অনুমতি নাই MM#3"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc410-as/strings.xml b/core/res/res/values-mcc310-mnc410-as/strings.xml
new file mode 100644
index 0000000..94b9726
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc410-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1593063035884873292">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="4477688981805467729">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc560-as/strings.xml b/core/res/res/values-mcc310-mnc560-as/strings.xml
new file mode 100644
index 0000000..6365190
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc560-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="2519618694918727742">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="7030488670186895244">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc950-as/strings.xml b/core/res/res/values-mcc310-mnc950-as/strings.xml
new file mode 100644
index 0000000..7a3af72
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc950-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="2418195136279399212">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="8920048244573695129">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc311-mnc180-as/strings.xml b/core/res/res/values-mcc311-mnc180-as/strings.xml
new file mode 100644
index 0000000..868c39b
--- /dev/null
+++ b/core/res/res/values-mcc311-mnc180-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="97745044956236881">"ছিমৰ অনুমতি নাই MM#3"</string>
+ <string name="mmcc_illegal_me" msgid="5766888847785331904">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc312-mnc670-as/strings.xml b/core/res/res/values-mcc312-mnc670-as/strings.xml
new file mode 100644
index 0000000..534d4e1
--- /dev/null
+++ b/core/res/res/values-mcc312-mnc670-as/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me" msgid="3649306773478362802">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-mcc313-mnc100-as/strings.xml b/core/res/res/values-mcc313-mnc100-as/strings.xml
new file mode 100644
index 0000000..350757c
--- /dev/null
+++ b/core/res/res/values-mcc313-mnc100-as/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mmcc_illegal_me" msgid="7320955531336937252">"ফ\'নৰ অনুমতি নাই MM#6"</string>
+</resources>
diff --git a/core/res/res/values-or-watch/strings.xml b/core/res/res/values-or-watch/strings.xml
new file mode 100644
index 0000000..4498c95
--- /dev/null
+++ b/core/res/res/values-or-watch/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଆପ୍ରୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଟି।"</string>
+ <string name="permgrouplab_sensors" msgid="202675452368612754">"ସେନ୍ସର୍"</string>
+</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
new file mode 100644
index 0000000..ccfc523
--- /dev/null
+++ b/core/res/res/values-or/strings.xml
@@ -0,0 +1,2133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="byteShort" msgid="8340973892742019101">"B"</string>
+ <string name="kilobyteShort" msgid="7542884022844556968">"kB"</string>
+ <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
+ <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
+ <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
+ <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled" msgid="4638956954852782576">"<ନାମହୀନ>"</string>
+ <string name="emptyPhoneNumber" msgid="7694063042079676517">"(କୌଣସି ଫୋନ୍ ନମ୍ବର ନାହିଁ)"</string>
+ <string name="unknownName" msgid="6867811765370350269">"ଅଜଣା"</string>
+ <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ଭଏସ୍ ମେଲ୍"</string>
+ <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
+ <string name="mmiError" msgid="5154499457739052907">"ସଂଯୋଗରେ ସମସ୍ୟା ଅଛି କିମ୍ବା ଅମାନ୍ୟ MMI କୋଡ୍।"</string>
+ <string name="mmiFdnError" msgid="5224398216385316471">"କେବଳ ସ୍ଥାୟୀ ଡାୟଲିଙ୍ଗ ନମ୍ବର୍ ପାଇଁ କାର୍ଯ୍ୟ ସୀମିତ ଅଟେ।"</string>
+ <string name="mmiErrorWhileRoaming" msgid="762488890299284230">"ଆପଣ ରୋମିଙ୍ଗରେ ଥିବାବେଳେ କଲ୍ ଫର୍ୱର୍ଡିଙ୍ଗ ସେଟିଙ୍ଗ ବଦଳାଇପାରିବେ ନାହିଁ।"</string>
+ <string name="serviceEnabled" msgid="8147278346414714315">"ସେବା ସକ୍ଷମ କରାଯାଇଥିଲା।"</string>
+ <string name="serviceEnabledFor" msgid="6856228140453471041">"ଏଥିପାଇଁ ସେବା ସକ୍ଷମ କରାଯାଇଥିଲା:"</string>
+ <string name="serviceDisabled" msgid="1937553226592516411">"ସେବାକୁ ଅକ୍ଷମ କରିଦିଆଯାଇଛି।"</string>
+ <string name="serviceRegistered" msgid="6275019082598102493">"ପଞ୍ଜିକରଣ ସଫଳ ହେଲା।"</string>
+ <string name="serviceErased" msgid="1288584695297200972">"ଲିଭାଇବା ସଫଳ ହେଲା।"</string>
+ <string name="passwordIncorrect" msgid="7612208839450128715">"ଭୁଲ ପାସୱର୍ଡ।"</string>
+ <string name="mmiComplete" msgid="8232527495411698359">"MMI ସମ୍ପୂର୍ଣ୍ଣ।"</string>
+ <string name="badPin" msgid="9015277645546710014">"ଆପଣ ଟାଇପ୍ କରିଥିବା ପୁରୁଣା PIN ଭୁଲ ଅଟେ।"</string>
+ <string name="badPuk" msgid="5487257647081132201">"ଆପଣ ଟାଇପ୍ କରିଥିବା PUK ଭୁଲ ଅଟେ।"</string>
+ <string name="mismatchPin" msgid="609379054496863419">"ଆପଣ ଟାଇପ୍ କରିଥିବା PINଗୁଡ଼ିକ ମେଳ ହେଉନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="invalidPin" msgid="3850018445187475377">"4 ରୁ 8ଟି ସଂଖ୍ୟା ବିଶିଷ୍ଟ ଏକ PIN ଟାଇପ୍ କରନ୍ତୁ।"</string>
+ <string name="invalidPuk" msgid="8761456210898036513">"ଏକ PUK ଟାଇପ୍ କରନ୍ତୁ, ଯାହାକି 8 ସଂଖ୍ୟା ବିଶିଷ୍ଟ କିମ୍ୱା ତା’ଠାରୁ ଅଧିକ ହୋଇଥିବ।"</string>
+ <string name="needPuk" msgid="919668385956251611">"ଆପଣଙ୍କ SIM କାର୍ଡ PUK ଲକ୍ ଅଛି। ଏହାକୁ ଅନଲକ୍ କରିବାକୁ PUK କୋଡ୍ ଟାଇପ୍ କରନ୍ତୁ।"</string>
+ <string name="needPuk2" msgid="4526033371987193070">"SIM କାର୍ଡରୁ ଅବରୋଧ ହଟାଇବା ପାଇଁ PUK2 ଟାଇପ୍ କରନ୍ତୁ।"</string>
+ <string name="enablePin" msgid="209412020907207950">"ସଫଳ ହେଲାନାହିଁ, SIM/RUIM ଲକ୍ କରନ୍ତୁ।"</string>
+ <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+ <item quantity="other">ଆଉ <xliff:g id="NUMBER_1">%d</xliff:g>ଟି ପ୍ରୟାସ ପରେ SIM ଲକ୍ ହୋଇଯିବ।</item>
+ <item quantity="one">ଆଉ <xliff:g id="NUMBER_0">%d</xliff:g>ଟି ପ୍ରୟାସ ପରେ SIM ଲକ୍ ହୋଇଯିବ।</item>
+ </plurals>
+ <string name="imei" msgid="2625429890869005782">"IMEI"</string>
+ <string name="meid" msgid="4841221237681254195">"MEID"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"ଇନକମିଙ୍ଗ କଲର୍ ଆଇଡି"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"ଆଉଟଗୋଇଙ୍ଗ୍ କଲର୍ ଆଇଡି"</string>
+ <string name="ColpMmi" msgid="3065121483740183974">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID"</string>
+ <string name="ColrMmi" msgid="4996540314421889589">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID କଟକଣା"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"କଲ୍ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+ <string name="CwMmi" msgid="9129678056795016867">"କଲ୍ ଅପେକ୍ଷାରତ"</string>
+ <string name="BaMmi" msgid="455193067926770581">"କଲ୍ ବ୍ୟାରିଙ୍ଗ୍"</string>
+ <string name="PwdMmi" msgid="7043715687905254199">"ପାସ୍ୱର୍ଡ ପରିବର୍ତ୍ତନ"</string>
+ <string name="PinMmi" msgid="3113117780361190304">"PIN ପରିବର୍ତ୍ତନ"</string>
+ <string name="CnipMmi" msgid="3110534680557857162">"କଲିଙ୍ଗ ନମ୍ୱର୍ ଉପସ୍ଥିତ"</string>
+ <string name="CnirMmi" msgid="3062102121430548731">"କଲିଙ୍ଗ ନମ୍ବର୍ ପ୍ରତିବନ୍ଧିତ"</string>
+ <string name="ThreeWCMmi" msgid="9051047170321190368">"ତିନି ପ୍ରକାରରେ କଲିଙ୍ଗ"</string>
+ <string name="RuacMmi" msgid="7827887459138308886">"ଅବାଞ୍ଛିତ ଅଜଣା କଲ୍ଗୁଡ଼ିକର ପ୍ରତ୍ୟାଖ୍ୟାନ"</string>
+ <string name="CndMmi" msgid="3116446237081575808">"କଲିଙ୍ଗ ନମ୍ବର୍ ଡେଲିଭରୀ"</string>
+ <string name="DndMmi" msgid="1265478932418334331">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"କଲର୍ ଆଇଡି ଡିଫଲ୍ଟ ଭାବରେ ପ୍ରତିବନ୍ଧିତ। ପରବର୍ତ୍ତୀ କଲ୍: ପ୍ରତିବନ୍ଧିତ"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"କଲର୍ ଆଇଡି ଡିଫଲ୍ଟ ଭାବରେ ପ୍ରତିବନ୍ଧିତ। ପରବର୍ତ୍ତୀ କଲ୍: ପ୍ରତିବନ୍ଧିତ ନୁହେଁ"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"କଲର୍ ଆଇଡି ଡିଫଲ୍ଟ ଭାବରେ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ। ପରବର୍ତ୍ତୀ କଲ୍: ପ୍ରତିବନ୍ଧିତ"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"କଲର୍ ଆଇଡି ଡିଫଲ୍ଟ ଭାବରେ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ। ପରବର୍ତ୍ତୀ କଲ୍: ପ୍ରତିବନ୍ଧିତ ନୁହେଁ"</string>
+ <string name="serviceNotProvisioned" msgid="8614830180508686666">"ସେବାର ସୁବିଧା ନାହିଁ।"</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"ଆପଣ କଲର୍ ID ସେଟିଙ୍ଗ ବଦଳାଇପାରିବେ ନାହିଁ।"</string>
+ <!-- no translation found for RestrictedOnDataTitle (1322504692764166532) -->
+ <skip />
+ <!-- no translation found for RestrictedOnEmergencyTitle (3646729271176394091) -->
+ <skip />
+ <!-- no translation found for RestrictedOnNormalTitle (3179574012752700984) -->
+ <skip />
+ <!-- no translation found for RestrictedOnAllVoiceTitle (158800171499150681) -->
+ <skip />
+ <!-- no translation found for RestrictedStateContent (4278821484643362350) -->
+ <skip />
+ <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ନେଟ୍ୱର୍କ ପର୍ଯ୍ୟନ୍ତ ପହଞ୍ଚିପାରୁ ନାହିଁ"</string>
+ <!-- no translation found for NetworkPreferenceSwitchSummary (7056776609127756440) -->
+ <skip />
+ <!-- no translation found for EmergencyCallWarningTitle (4790413876281901612) -->
+ <skip />
+ <!-- no translation found for EmergencyCallWarningSummary (8973232888021643293) -->
+ <skip />
+ <!-- no translation found for notification_channel_network_alert (4427736684338074967) -->
+ <skip />
+ <!-- no translation found for notification_channel_call_forward (2419697808481833249) -->
+ <skip />
+ <!-- no translation found for notification_channel_emergency_callback (6686166232265733921) -->
+ <skip />
+ <!-- no translation found for notification_channel_mobile_data_status (4575131690860945836) -->
+ <skip />
+ <!-- no translation found for notification_channel_sms (3441746047346135073) -->
+ <skip />
+ <!-- no translation found for notification_channel_voice_mail (3954099424160511919) -->
+ <skip />
+ <!-- no translation found for notification_channel_wfc (2130802501654254801) -->
+ <skip />
+ <!-- no translation found for notification_channel_sim (4052095493875188564) -->
+ <skip />
+ <string name="peerTtyModeFull" msgid="6165351790010341421">"ପୀଆର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ FULL ଅଟେ"</string>
+ <string name="peerTtyModeHco" msgid="5728602160669216784">"ପୀଅର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ HCO ଅଟେ"</string>
+ <string name="peerTtyModeVco" msgid="1742404978686538049">"ପୀଅର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ VCO ଅଟେ"</string>
+ <string name="peerTtyModeOff" msgid="3280819717850602205">"ପୀଅର୍ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍ OFF ଅଛି"</string>
+ <string name="serviceClassVoice" msgid="1258393812335258019">"ଭଏସ୍"</string>
+ <string name="serviceClassData" msgid="872456782077937893">"ଡାଟା"</string>
+ <string name="serviceClassFAX" msgid="5566624998840486475">"ଫାକ୍ସ"</string>
+ <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
+ <string name="serviceClassDataAsync" msgid="4523454783498551468">"ଏସିଙ୍କ୍"</string>
+ <string name="serviceClassDataSync" msgid="7530000519646054776">"ସିଙ୍କ୍"</string>
+ <string name="serviceClassPacket" msgid="6991006557993423453">"ପ୍ୟାକେଟ୍"</string>
+ <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="roamingText0" msgid="7170335472198694945">"ରୋମିଙ୍ଗ ସୂଚକ ଅନ୍ ଅଛି"</string>
+ <string name="roamingText1" msgid="5314861519752538922">"ରୋମିଙ୍ଗ ସୂଚକ ଅଫ୍ ଅଛି"</string>
+ <string name="roamingText2" msgid="8969929049081268115">"ରୋମିଙ୍ଗ ସୂଚକ ଧପ୍ ଧପ୍ ହେଉଛି"</string>
+ <string name="roamingText3" msgid="5148255027043943317">"ନିକଟସ୍ଥ ଅଞ୍ଚଳ ବାହାରେ"</string>
+ <string name="roamingText4" msgid="8808456682550796530">"ବିଲଡିଙ୍ଗ ବାହାରେ"</string>
+ <string name="roamingText5" msgid="7604063252850354350">"ରୋମିଙ୍ଗ - ପସନ୍ଦର ସିଷ୍ଟମ୍"</string>
+ <string name="roamingText6" msgid="2059440825782871513">"ରୋମିଙ୍ଗ - ଉପଲବ୍ଧ ସେବା"</string>
+ <string name="roamingText7" msgid="7112078724097233605">"ରୋମିଙ୍ଗ - ଆଲାୟାନ୍ସ ପାର୍ଟନର୍"</string>
+ <string name="roamingText8" msgid="5989569778604089291">"ରୋମିଙ୍ଗ - ପ୍ରିମିୟମ୍ ପାର୍ଟନର୍"</string>
+ <string name="roamingText9" msgid="7969296811355152491">"ରୋମିଙ୍ଗ - ସମ୍ପୂର୍ଣ୍ଣ ସେବା କାର୍ଯ୍ୟକ୍ଷମତା"</string>
+ <string name="roamingText10" msgid="3992906999815316417">"ରୋମିଙ୍ଗ - ଆଂଶିକ ସେବା କାର୍ଯ୍ୟକ୍ଷମତା"</string>
+ <string name="roamingText11" msgid="4154476854426920970">"ରୋମିଙ୍ଗ ବ୍ୟାନର୍ ଅନ୍ ଅଛି"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"ରୋମିଙ୍ଗ ବ୍ୟାନର୍ ଅଫ୍ ଅଛି"</string>
+ <string name="roamingTextSearching" msgid="8360141885972279963">"ସେବା ଖୋଜାଯାଉଛି"</string>
+ <string name="wfcRegErrorTitle" msgid="2301376280632110664">"ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</string>
+ <!-- no translation found for wfcOperatorErrorAlertMessages:0 (3910386316304772394) -->
+ <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (7472393097168811593) -->
+ <!-- no translation found for wfcSpnFormats:0 (6830082633573257149) -->
+ <!-- no translation found for wfcSpnFormats:1 (4397097370387921767) -->
+ <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ଅଫ୍"</string>
+ <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ପସନ୍ଦ କରାଯାଇଥିବା ୱାଇ-ଫାଇ"</string>
+ <!-- no translation found for wfc_mode_cellular_preferred_summary (1988279625335345908) -->
+ <skip />
+ <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"କେବଳ ୱାଇ-ଫାଇ"</string>
+ <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ଫରୱାର୍ଡ କରାଯାଇନାହିଁ"</string>
+ <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ସେକେଣ୍ଡ ପରେ"</string>
+ <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ଫରୱାର୍ଡ କରାଯାଇନାହିଁ"</string>
+ <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ଫର୍ୱର୍ଡ କରାଗଲା ନାହିଁ"</string>
+ <string name="fcComplete" msgid="3118848230966886575">"ଫିଚର୍ କୋଡ୍ ସମ୍ପୂର୍ଣ୍ଣ।"</string>
+ <string name="fcError" msgid="3327560126588500777">"ସଂଯୋଗରେ ସମସ୍ୟା କିମ୍ୱା ଅମାନ୍ୟ ଫିଚର୍ କୋଡ୍।"</string>
+ <string name="httpErrorOk" msgid="1191919378083472204">"ଠିକ୍ ଅଛି"</string>
+ <string name="httpError" msgid="7956392511146698522">"ନେଟ୍ୱର୍କରେ ଏକ ତ୍ରୁଟି ଥିଲା।"</string>
+ <string name="httpErrorLookup" msgid="4711687456111963163">"URL ମିଳିଲା ନାହିଁ।"</string>
+ <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"ସାଇଟ୍ ପ୍ରମାଣୀକରଣ ସ୍କିମ୍ ସପୋର୍ଟ କରୁନାହିଁ।"</string>
+ <string name="httpErrorAuth" msgid="1435065629438044534">"ସ୍ୱୀକୃତି ଦେଇପାରିଲା ନାହିଁ।"</string>
+ <string name="httpErrorProxyAuth" msgid="1788207010559081331">"ପ୍ରୋକ୍ସୀ ସର୍ଭର୍ ଦ୍ୱାରା ସ୍ୱୀକୃତି ଦିଆଯାଇପାରିଲା ନାହିଁ।"</string>
+ <string name="httpErrorConnect" msgid="8714273236364640549">"ସର୍ଭର୍ ସହ ସଂଯୋଗ କରିପାରିଲା ନାହିଁ।"</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"ସର୍ଭର୍ ସହ ଯୋଗାଯୋଗ କରିପାରିଲା ନାହିଁ। ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="httpErrorTimeout" msgid="4743403703762883954">"ସର୍ଭରକୁ ସଂଯୋଗର ସମୟ ସୀମା ସମାପ୍ତ ହୋଇଯାଇଛି।"</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"ଏହି ପୃଷ୍ଠାରେ ବହୁତ ସର୍ଭର୍ ରିଡାଇରେକ୍ଟ ରହିଛି।"</string>
+ <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"ପ୍ରୋଟୋକଲ୍ ସପୋର୍ଟ କରୁନାହିଁ।"</string>
+ <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"ଏକ ନିରାପଦ ସଂଯୋଗ ସ୍ଥାପନ କରିପାରିଲା ନାହିଁ।"</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"URL ବୈଧ ନଥିବାରୁ ପୃଷ୍ଠାଟି ଖୋଲିପାରିଲା ନାହିଁ।"</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"ଫାଇଲ୍ ଆକ୍ସେସ୍ କରିପାରିଲା ନାହିଁ।"</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"ଅନୁରୋଧ କରାଯାଇଥିବା ଫାଇଲ୍ ପାଇଲା ନାହିଁ।"</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"ଅନେକ ଅନୁରୋଧ ଉପରେ କାମ ଚାଲୁଛି। ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g>ରେ ସାଇନ୍-ଇନ୍ ତ୍ରୁଟି"</string>
+ <string name="contentServiceSync" msgid="8353523060269335667">"ସିଙ୍କ୍"</string>
+ <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ସିଙ୍କ୍"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"ଅତ୍ୟଧିକ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ଡିଲିଟ୍ କରିଦିଏ।"</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"ଟାବଲେଟ୍ ଷ୍ଟୋରେଜ୍ ପୂର୍ଣ୍ଣ ହୋଇଯାଇଛି। ସ୍ଥାନ ଖାଲି କରିବା ପାଇଁ କିଛି ଫାଇଲ୍ ଡିଲିଟ୍ କରନ୍ତୁ।"</string>
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"ୱାଚ୍ ଷ୍ଟୋରେଜ୍ ପୂର୍ଣ୍ଣ ହୋଇଯାଇଛି। ସ୍ଥାନ ଖାଲି କରିବାକୁ କିଛି ଫାଇଲ୍ ଡିଲିଟ୍ କରନ୍ତୁ।"</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"ଟିଭିର ଷ୍ଟୋରେଜ୍ ପୂର୍ଣ୍ଣ ହୋଇଯାଇଛି। ସ୍ପେସ୍ ଖାଲି କରିବାକୁ କିଛି ଫାଇଲ୍ ଡିଲିଟ୍ କରନ୍ତୁ।"</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"ଫୋନ୍ ଷ୍ଟୋରେଜ୍ ପୂର୍ଣ୍ଣ ହୋଇଯାଇଛି। ସ୍ଥାନ ଖାଲି କରିବା ପାଇଁ କିଛି ଫାଇଲ୍ ଡିଲିଟ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for ssl_ca_cert_warning (5106721205300213569) -->
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ଅଜଣା ତୃତୀୟ ପକ୍ଷ ଅନୁଯାୟୀ"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_administrator (3541729986326153557) -->
+ <skip />
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> ଅନୁଯାୟୀ"</string>
+ <string name="work_profile_deleted" msgid="5005572078641980632">"ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଡିଲିଟ୍ ହେଲା"</string>
+ <!-- no translation found for work_profile_deleted_description (1100529432509639864) -->
+ <skip />
+ <!-- no translation found for work_profile_deleted_details (6307630639269092360) -->
+ <skip />
+ <!-- no translation found for work_profile_deleted_description_dpm_wipe (8823792115612348820) -->
+ <skip />
+ <!-- no translation found for work_profile_deleted_reason_maximum_password_failure (8986903510053359694) -->
+ <skip />
+ <!-- no translation found for network_logging_notification_title (6399790108123704477) -->
+ <skip />
+ <!-- no translation found for network_logging_notification_text (7930089249949354026) -->
+ <skip />
+ <string name="factory_reset_warning" msgid="5423253125642394387">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
+ <!-- no translation found for factory_reset_message (9024647691106150160) -->
+ <skip />
+ <!-- no translation found for printing_disabled_by (8936832919072486965) -->
+ <skip />
+ <string name="me" msgid="6545696007631404292">"ମୁଁ"</string>
+ <string name="power_dialog" product="tablet" msgid="8545351420865202853">"ଟାବଲେଟ୍ର ବିକଳ୍ପ"</string>
+ <string name="power_dialog" product="tv" msgid="6153888706430556356">"ଟିଭି ବିକଳ୍ପଗୁଡ଼ିକ"</string>
+ <string name="power_dialog" product="default" msgid="1319919075463988638">"ଫୋନ୍ ବିକଳ୍ପ"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"ୱେୟାରଲେସ୍କୁ ଚାଲୁ କରନ୍ତୁ"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"ୱେୟାରଲେସ୍କୁ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="screen_lock" msgid="799094655496098153">"ସ୍କ୍ରୀନ୍ ଲକ୍"</string>
+ <string name="power_off" msgid="4266614107412865048">"ପାୱାର୍ ଅଫ୍"</string>
+ <string name="silent_mode_silent" msgid="319298163018473078">"ରିଙ୍ଗର୍ ଅଫ୍ ଅଛି"</string>
+ <string name="silent_mode_vibrate" msgid="7072043388581551395">"ରିଙ୍ଗର୍ କମ୍ପନ"</string>
+ <string name="silent_mode_ring" msgid="8592241816194074353">"ରିଙ୍ଗର୍ ଅନ୍ ଅଛି"</string>
+ <string name="reboot_to_update_title" msgid="6212636802536823850">"Android ସିଷ୍ଟମ୍ ଅପଡେଟ୍"</string>
+ <string name="reboot_to_update_prepare" msgid="6305853831955310890">"ଅପଡେଟ୍ କରିବାକୁ ପ୍ରସ୍ତୁତ କରାଯାଉଛି…"</string>
+ <string name="reboot_to_update_package" msgid="3871302324500927291">"ଅପଡେଟ୍ ପ୍ୟାକେଜ୍ ପ୍ରୋସେସ୍ କରାଯାଉଛି…"</string>
+ <string name="reboot_to_update_reboot" msgid="6428441000951565185">"ରିଷ୍ଟାର୍ଟ କରାଯାଉଛି…"</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍"</string>
+ <string name="reboot_to_reset_message" msgid="2432077491101416345">"ରିଷ୍ଟାର୍ଟ କରାଯାଉଛି…"</string>
+ <string name="shutdown_progress" msgid="2281079257329981203">"ବନ୍ଦ କରାଯାଉଛି…"</string>
+ <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"ଆପଣଙ୍କ ଟାବଲେଟ୍ ବନ୍ଦ ହୋଇଯିବ।"</string>
+ <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"ଆପଣଙ୍କ ଟିଭି ବନ୍ଦ ହେବ।"</string>
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ଆପଣଙ୍କ ଘଣ୍ଟା ବନ୍ଦ ହୋଇଯିବ।"</string>
+ <string name="shutdown_confirm" product="default" msgid="649792175242821353">"ଆପଣଙ୍କ ଫୋନ୍ ବନ୍ଦ ହୋଇଯିବ।"</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"ଆପଣ ବନ୍ଦ କରିବାକୁ ଚାହାନ୍ତି?"</string>
+ <string name="reboot_safemode_title" msgid="7054509914500140361">"ନିରାପଦ ମୋଡ୍ରେ ରିବୁଟ୍ କରନ୍ତୁ"</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"ଆପଣ ନିରାପଦ ମୋଡ୍ରେ ରିବୁଟ୍ କରିବେ କି? ଆପଣ ଇନଷ୍ଟଲ୍ କରିଥିବା ସମସ୍ତ ତୃତୀୟ ପକ୍ଷ ଆପ୍ଲିକେଶନ୍, ଏହାଦ୍ୱାରା ଅକ୍ଷମ ହୋଇଯିବ। ଆପଣ ପୁଣି ରିବୁଟ୍ କରିବା ପରେ ସେଗୁଡ଼ିକ ରିଷ୍ଟୋର୍ ହେବ।"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"କିଛି ସମୟ ପୂର୍ବରୁ"</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"କୌଣସି ସମ୍ପ୍ରତି ଆପ୍ ନାହିଁ।"</string>
+ <string name="global_actions" product="tablet" msgid="408477140088053665">"ଟାବଲେଟ ବିକଳ୍ପ"</string>
+ <string name="global_actions" product="tv" msgid="7240386462508182976">"ଟିଭିର ବିକଳ୍ପ"</string>
+ <string name="global_actions" product="default" msgid="2406416831541615258">"ଫୋନ ବିକଳ୍ପ"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"ସ୍କ୍ରୀନ୍ ଲକ୍"</string>
+ <string name="global_action_power_off" msgid="4471879440839879722">"ପାୱାର୍ ଅଫ୍"</string>
+ <string name="global_action_emergency" msgid="7112311161137421166">"ଜରୁରୀକାଳୀନ"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"ବଗ୍ ରିପୋର୍ଟ"</string>
+ <!-- no translation found for global_action_logout (935179188218826050) -->
+ <skip />
+ <!-- no translation found for global_action_screenshot (8329831278085426283) -->
+ <skip />
+ <string name="bugreport_title" msgid="2667494803742548533">"ବଗ୍ ରିପୋର୍ଟ ନିଅନ୍ତୁ"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"ଇ-ମେଲ୍ ମେସେଜ୍ ଭାବରେ ପଠାଇବାକୁ, ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ଡିଭାଇସ୍ ବିଷୟରେ ଏହା ସୂଚନା ସଂଗ୍ରହ କରିବ। ବଗ୍ ରିପୋର୍ଟ ଆରମ୍ଭ ହେବାପରଠାରୁ ଏହାକୁ ପଠାଇବା ପାଇଁ କିଛି ସମୟ ଲାଗିବ, ଦୟାକରି ଧୈର୍ଯ୍ୟ ରଖନ୍ତୁ।"</string>
+ <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"ଇଣ୍ଟରାକ୍ଟିଭ୍ ରିପୋର୍ଟ"</string>
+ <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"ଅଧିକାଂଶ କ୍ଷେତ୍ରରେ ଏହା ବ୍ୟବହାର କରନ୍ତୁ। ଏହାଦ୍ୱାରା ଆପଣ ରିପୋର୍ଟର ପ୍ରଗତିକୁ ଟ୍ରାକ୍ କରିପାରିବେ, ସମସ୍ୟା ଉପରେ ଅଧିକ ବିବରଣୀ ଲେଖିପାରିବେ ଏବଂ ସ୍କ୍ରୀନଶଟ୍ ନେଇପାରିବେ। ଏହା କିଛି କମ୍-ବ୍ୟବହାର କରାଯାଇଥିବା ବିଭାଗକୁ ଛାଡ଼ିଦେଇପାରେ, ଯାହା ରିପୋର୍ଟ କରିବାକୁ ଅଧିକ ସମୟ ନିଏ।"</string>
+ <string name="bugreport_option_full_title" msgid="6354382025840076439">"ପୂର୍ଣ୍ଣ ରିପୋର୍ଟ"</string>
+ <string name="bugreport_option_full_summary" msgid="7210859858969115745">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ପ୍ରତିକ୍ରିୟା ଦେଉନଥିବାବେଳେ କିମ୍ବା ବହୁତ ଧୀରେ ଚାଲୁଥିବାବେଳେ କିମ୍ବା ଆପଣ ସମସ୍ତ ରିପୋର୍ଟ ବିଭାଗ ଆବଶ୍ୟକ କରିବାବେଳେ ସିଷ୍ଟମର କମ୍ ହସ୍ତକ୍ଷେପ ପାଇଁ ଏହି ବିକଳ୍ପ ବ୍ୟବହାର କରନ୍ତୁ। ଅଧିକ ବିବରଣୀ ଲେଖିବାକୁ କିମ୍ବା ଅତିରିକ୍ତ ସ୍କ୍ରୀନଶଟ୍ ନେବାକୁ ଅନୁମତି ଦିଏନାହିଁ।"</string>
+ <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> ସେକେଣ୍ଡରେ ବଗ୍ ରିପୋର୍ଟ ପାଇଁ ସ୍କ୍ରୀନଶଟ୍ ନେଉଛି।</item>
+ <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> ସେକେଣ୍ଡରେ ବଗ୍ ରିପୋର୍ଟ ପାଇଁ ସ୍କ୍ରୀନଶଟ୍ ନେଉଛି।</item>
+ </plurals>
+ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string>
+ <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ସାଉଣ୍ଡ ଅଫ୍ ଅଛି"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"ସାଉଣ୍ଡ ଅନ୍ ଅଛି"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍ ଅନ୍ ଅଛି"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍ ଅଫ୍ ଅଛି"</string>
+ <!-- no translation found for global_action_toggle_battery_saver (708515500418994208) -->
+ <skip />
+ <!-- no translation found for global_action_battery_saver_on_status (484059130698197787) -->
+ <skip />
+ <!-- no translation found for global_action_battery_saver_off_status (75550964969478405) -->
+ <skip />
+ <string name="global_action_settings" msgid="1756531602592545966">"ସେଟିଙ୍ଗ"</string>
+ <string name="global_action_assist" msgid="3892832961594295030">"ସହାୟକ"</string>
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"ଭଏସ୍ ସହାୟକ"</string>
+ <!-- no translation found for global_action_lockdown (1099326950891078929) -->
+ <skip />
+ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <!-- no translation found for notification_hidden_text (6351207030447943784) -->
+ <skip />
+ <!-- no translation found for notification_channel_virtual_keyboard (6969925135507955575) -->
+ <skip />
+ <!-- no translation found for notification_channel_physical_keyboard (7297661826966861459) -->
+ <skip />
+ <!-- no translation found for notification_channel_security (7345516133431326347) -->
+ <skip />
+ <!-- no translation found for notification_channel_car_mode (3553380307619874564) -->
+ <skip />
+ <!-- no translation found for notification_channel_account (7577959168463122027) -->
+ <skip />
+ <!-- no translation found for notification_channel_developer (7579606426860206060) -->
+ <skip />
+ <!-- no translation found for notification_channel_updates (4794517569035110397) -->
+ <skip />
+ <!-- no translation found for notification_channel_network_status (5025648583129035447) -->
+ <skip />
+ <!-- no translation found for notification_channel_network_alerts (2895141221414156525) -->
+ <skip />
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
+ <!-- no translation found for notification_channel_vpn (8330103431055860618) -->
+ <skip />
+ <!-- no translation found for notification_channel_device_admin (1568154104368069249) -->
+ <skip />
+ <!-- no translation found for notification_channel_alerts (4496839309318519037) -->
+ <skip />
+ <!-- no translation found for notification_channel_retail_mode (6088920674914038779) -->
+ <skip />
+ <!-- no translation found for notification_channel_usb (9006850475328924681) -->
+ <skip />
+ <!-- no translation found for notification_channel_heavy_weight_app (6218742927792852607) -->
+ <skip />
+ <!-- no translation found for notification_channel_foreground_service (3931987440602669158) -->
+ <skip />
+ <!-- no translation found for foreground_service_app_in_background (1060198778219731292) -->
+ <skip />
+ <!-- no translation found for foreground_service_apps_in_background (7175032677643332242) -->
+ <skip />
+ <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
+ <skip />
+ <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
+ <skip />
+ <string name="safeMode" msgid="2788228061547930246">"ସୁରକ୍ଷିତ ମୋଡ୍"</string>
+ <string name="android_system_label" msgid="6577375335728551336">"Android ସିଷ୍ଟମ୍"</string>
+ <!-- no translation found for user_owner_label (8836124313744349203) -->
+ <skip />
+ <!-- no translation found for managed_profile_label (8947929265267690522) -->
+ <skip />
+ <string name="permgrouplab_contacts" msgid="3657758145679177612">"ଯୋଗାଯୋଗ"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ଆପଣଙ୍କ ଯୋଗାଯୋଗ ଆକ୍ସେସ୍ କରେ"</string>
+ <!-- no translation found for permgrouprequest_contacts (1601591667800538208) -->
+ <skip />
+ <string name="permgrouplab_location" msgid="7275582855722310164">"ଲୋକେଶନ୍"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"ଏହି ଡିଭାଇସ୍ର ଲୋକେଶନ୍ ଆକ୍ସେସ୍ କରେ"</string>
+ <!-- no translation found for permgrouprequest_location (8903573681261610809) -->
+ <skip />
+ <string name="permgrouplab_calendar" msgid="5863508437783683902">"କ୍ୟାଲେଣ୍ଡର୍"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"ଆପଣଙ୍କ କ୍ୟାଲେଣ୍ଡର୍ ଆକ୍ସେସ୍ କରେ"</string>
+ <!-- no translation found for permgrouprequest_calendar (6704529828699071445) -->
+ <skip />
+ <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS ମେସେଜ୍ ପଠାନ୍ତୁ ଓ ଦେଖନ୍ତୁ"</string>
+ <!-- no translation found for permgrouprequest_sms (605618939583628306) -->
+ <skip />
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"ଷ୍ଟୋରେଜ୍"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ଥିବା ଫଟୋ, ମିଡିଆ ଓ ଫାଇଲ୍ ଆକ୍ସେସ୍ କରେ"</string>
+ <!-- no translation found for permgrouprequest_storage (7429669910547860218) -->
+ <skip />
+ <string name="permgrouplab_microphone" msgid="171539900250043464">"ମାଇକ୍ରୋଫୋନ୍"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ଅଡିଓ ରେକର୍ଡ କରେ"</string>
+ <!-- no translation found for permgrouprequest_microphone (8065941268709600606) -->
+ <skip />
+ <string name="permgrouplab_camera" msgid="4820372495894586615">"କ୍ୟାମେରା"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"ଫଟୋ ନିଏ ଓ ଭିଡିଓ ରେକର୍ଡ କରେ"</string>
+ <!-- no translation found for permgrouprequest_camera (810824326507258410) -->
+ <skip />
+ <string name="permgrouplab_phone" msgid="5229115638567440675">"ଫୋନ୍"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"ଫୋନ୍ କଲ୍ କରେ ଏବଂ ପରିଚାଳନା କରେ"</string>
+ <!-- no translation found for permgrouprequest_phone (7084161459732093690) -->
+ <skip />
+ <string name="permgrouplab_sensors" msgid="416037179223226722">"ବଡୀ ସେନ୍ସର୍"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ଆପଣଙ୍କ ଗୁରୁତପୂର୍ଣ୍ଣ ସଂକେତଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର୍ ଡାଟା ଆକ୍ସେସ୍ କରେ"</string>
+ <!-- no translation found for permgrouprequest_sensors (8631146669524259656) -->
+ <skip />
+ <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"ୱିଣ୍ଡୋ କଣ୍ଟେଣ୍ଟ ହାସଲ କରନ୍ତୁ"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"ଆପଣ କାମ କରୁଥିବା ୱିଣ୍ଡୋର କଣ୍ଟେଣ୍ଟକୁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"ସ୍ପର୍ଶ ଦ୍ୱାରା ଏକ୍ସପ୍ଲୋର୍ ଅନ୍ କରନ୍ତୁ"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"ଟାପ୍ କରାଯାଇଥିବା ଆଇଟମ୍ଗୁଡ଼ିକୁ ବଡ଼ ପାଟିରେ କୁହାଯିବ ଏବଂ ଜେଶ୍ଚର୍ ବ୍ୟବହାର କରି ସ୍କ୍ରୀନ୍ ଏକ୍ସପ୍ଲୋର୍ କରାଯିବ।"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"ଆପଣ ଟାଇପ୍ କରିବା ଟେକ୍ସଟ୍କୁ ଧ୍ୟାନଦେଇ ଦେଖନ୍ତୁ"</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"ବ୍ୟକ୍ତିଗତ ଡାଟା ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି, କ୍ରେଡିଟ୍ କାର୍ଡ ନମ୍ବର ଓ ପାସ୍ୱର୍ଡ।"</string>
+ <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"ଡିସପ୍ଲେ ମେଗ୍ନିଫିକେଶନ୍ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+ <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"ଡିସପ୍ଲେର ଜୁମ୍ ସ୍ତର ଓ ପୋଜିସନିଙ୍ଗ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"ଜେଶ୍ଚର୍ କରନ୍ତୁ"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"ଟାପ୍, ସ୍ୱାଇପ୍, ପିଞ୍ଚ ଓ ଅନ୍ୟାନ୍ୟ ଜେଶ୍ଚର୍ ସମ୍ପାଦନ କରିପାରିବ।"</string>
+ <!-- no translation found for capability_title_canCaptureFingerprintGestures (6309568287512278670) -->
+ <skip />
+ <!-- no translation found for capability_desc_canCaptureFingerprintGestures (4386487962402228670) -->
+ <skip />
+ <string name="permlab_statusBar" msgid="7417192629601890791">"ଷ୍ଟାଟସ୍ ବାର୍କୁ ଅକ୍ଷମ କିମ୍ୱା ସଂଶୋଧନ କରନ୍ତୁ"</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"ଆପ୍କୁ, ସ୍ଥିତି ବାର୍ ଅକ୍ଷମ କରିବାକୁ କିମ୍ବା ସିଷ୍ଟମ୍ ଆଇକନ୍ ଯୋଡ଼ିବା କିମ୍ବା ବାହାର କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_statusBarService" msgid="4826835508226139688">"ଷ୍ଟାଟସ୍ ବାର୍ ରହିବାକୁ ଦିଅନ୍ତୁ"</string>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"ଆପ୍ଟିକୁ ସ୍ଥିତି ବାର୍ ହେବାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ସ୍ଥିତି ବାର୍କୁ ବଡ଼/ଛୋଟ କରନ୍ତୁ"</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"ଷ୍ଟାଟସ୍ ବାର୍କୁ ବଡ଼ କିମ୍ବା ଛୋଟ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_install_shortcut" msgid="4279070216371564234">"ଶର୍ଟକଟ୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_install_shortcut" msgid="8341295916286736996">"ୟୁଜର୍ଙ୍କ ବିନା ବାଧାରେ ହୋମ୍ସ୍କ୍ରୀନ୍ ସର୍ଟକଟ୍ ଯୋଡ଼ିବାକୁ ଏକ ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ଶର୍ଟକଟ୍ ଅନଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ୟୁଜର୍ଙ୍କ ବିନା ବାଧାରେ ହୋମ୍ସ୍କ୍ରୀନ୍ର ଶର୍ଟକଟ୍ ବାହାର କରିବା ପାଇଁ ଗୋଟିଏ ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ଆଉଟ୍ଗୋଇଙ୍ଗ କଲ୍କୁ ଅନ୍ୟ ରୁଟ୍ ଦିଅନ୍ତୁ"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ଭିନ୍ନ ନମ୍ବରକୁ କଲ୍ ରିଡାଇରେକ୍ଟ କରିବା କିମ୍ବା ଏକାଠି କଲ୍ ଖାରଜ କରିବା ବିକଳ୍ପ ସହ ଆଉଟ୍ଗୋଇଙ୍ଗ କଲ୍ କରିବାବେଳେ ଡାୟଲ୍ କରାଯାଉଥିବା ନମ୍ବର ଦେଖିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <!-- no translation found for permlab_answerPhoneCalls (4077162841226223337) -->
+ <skip />
+ <!-- no translation found for permdesc_answerPhoneCalls (2901889867993572266) -->
+ <skip />
+ <string name="permlab_receiveSms" msgid="8673471768947895082">"ଟେକ୍ସଟ୍ ମେସେଜ୍ (SMS) ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"SMS ମେସେଜ୍ ପ୍ରାପ୍ତ କରିବାକୁ ତଥା ପ୍ରକ୍ରିୟା କରାଇବାକୁ ଆପ୍ଟିକୁ ଅନୁମତି ଦିଏ। ଏହାର ଅର୍ଥ ହେଉଛି, ଆପଣଙ୍କ ଡିଭାଇସ୍କୁ ପଠାଯାଇଥିବା ମେସେଜ୍ ଆପଣଙ୍କୁ ନଦେଖାଇ ଆପ୍ଟି ମନିଟର୍ କିମ୍ବା ଡିଲିଟ୍ କରିପାରେ।"</string>
+ <string name="permlab_receiveMms" msgid="1821317344668257098">"ଟେକ୍ସଟ୍ ମେସେଜ୍ (MMS) ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+ <string name="permdesc_receiveMms" msgid="533019437263212260">"MMS ମେସେଜ୍ ପ୍ରାପ୍ତ କରିବାକୁ ତଥା ପ୍ରକ୍ରିୟା କରାଇବାକୁ ଆପ୍ଟିକୁ ଅନୁମତି ଦିଏ। ଏହାର ଅର୍ଥ, ଆପଣଙ୍କ ଡିଭାଇସ୍କୁ ପଠାଯାଇଥିବା ମେସେଜ୍ ଆପଣଙ୍କୁ ନଦେଖାଇ ଆପ୍ଟି ମନିଟର୍ କିମ୍ବା ଡିଲିଟ୍ କରିପାରେ।"</string>
+ <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ମେସେଜ୍ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ପ୍ରାପ୍ତ ହୋଇଥିବା ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ମେସେଜ୍ ପଢିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଜରୁରୀକାଳୀନ ଅବସ୍ଥା ବିଷୟରେ ଆପଣଙ୍କୁ ସତର୍କ କରାଇବାକୁ କିଛି ଲୋକେଶନ୍ରେ ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ସତର୍କ ଡେଲିଭର୍ କରାଯାଇଥାଏ। ଏକ ଜରୁରୀକାଳୀନ ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ପ୍ରାପ୍ତ ହେବାପରେ ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ଡିଭାଇସ୍ର କାର୍ଯ୍ୟକ୍ଷମତା କିମ୍ବା ସଞ୍ଚାଳନାରେ ବାଧା ପହଞ୍ଚାଇପାରନ୍ତି।"</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ସବସ୍କ୍ରାଇବ୍ ହୋଇଥିବା ଫୀଡ୍କୁ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"ଆପ୍କୁ, କିଛି ସମୟ ପୂର୍ବରୁ ସିଙ୍କ ହୋଇଥିବା ଫୀଡ୍ ବିଷୟରେ ବିବରଣୀ ପ୍ରାପ୍ତ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"SMS ମେସେଜ୍ ପଠାନ୍ତୁ ଓ ଦେଖନ୍ତୁ"</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"ଆପ୍କୁ SMS ମେସେଜ୍ ପଠେଇବାକୁ ଅନୁମତି ଦେଇଥାଏ। ଏହାଦ୍ୱାରା ଅପ୍ରତ୍ୟାଶିତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ। ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ବିନା ସ୍ୱୀକୃତିରେ ମେସେଜ୍ ପଠାଇ, ଆପଣଙ୍କ ପଇସା ଖର୍ଚ୍ଚ କରାଇପାରେ।"</string>
+ <string name="permlab_readSms" msgid="8745086572213270480">"ଆପଣଙ୍କ ଟେକ୍ସଟ୍ ମେସେଜ୍ (SMS କିମ୍ବା MMS) ପଢ଼ନ୍ତୁ"</string>
+ <!-- no translation found for permdesc_readSms (4741697454888074891) -->
+ <skip />
+ <!-- no translation found for permdesc_readSms (5796670395641116592) -->
+ <skip />
+ <string name="permdesc_readSms" product="default" msgid="6826832415656437652">"ଆପଣଙ୍କ ଫୋନ୍ରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ସମସ୍ତ SMS (ଟେକ୍ସଟ୍) ମେସେଜ୍ ଏହି ଆପ୍ ପଢ଼ିପାରେ।"</string>
+ <string name="permlab_receiveWapPush" msgid="5991398711936590410">"ଟେକ୍ସଟ୍ ମେସେଜ୍ (WAP) ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"ଆପ୍କୁ WAP ମେସେଜିଙ୍ଗକୁ ପ୍ରାପ୍ତ ଓ ବିକାଶ କରିବାକୁ ଦେଇଥାଏ। ଏହି ଅନୁମତିରେ ଆପଣ ସେମାନଙ୍କୁ ଦେଖାଯାଇଥିବା ମେସେଜ୍ ଉପରେ ନଜର ରଖିବା ଏବଂ ଡିଲିଟ୍ କରିବାର କ୍ଷମତା ସାମିଲ୍ ଅଛି।"</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"ଚାଲୁଥିବା ଆପ୍ଗୁଡ଼ିକୁ ପୁନଃପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"ବର୍ତ୍ତମାନ ତଥା ନିକଟରେ ଚାଲୁଥିବା କାର୍ଯ୍ୟ ବିଷୟରେ ସୂଚନାକୁ ହାସଲ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଏହାଦ୍ୱାରା ଆପଟି ଡିଭାଇସ୍ର କେଉଁ ଆପ୍ଲିକେଶନ୍ରେ ଉପଯୋଗ କରାଯାଇଥିଲା, ତାହାର ସୂଚନାକୁ ଜାଣିପାରେ।"</string>
+ <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"ପ୍ରୋଫାଇଲ୍ ଓ ଡିଭାଇସ୍ ମାଲିକଙ୍କୁ ପରିଚାଳନା କରେ"</string>
+ <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"ପ୍ରୋଫାଇଲ୍ ମାଲିକ ଓ ଡିଭାଇସ୍ ମାଲିକଙ୍କ ପ୍ରୋଫାଇଲ୍ ସେଟ୍ କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"ଚାଲୁଥିବା ଆପ୍ଗୁଡ଼ିକର କ୍ରମକୁ ପୁଣି ସଜାନ୍ତୁ"</string>
+ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"ଆପ୍ଟି, ଆପଣ କରୁଥିବା କାମକୁ ଫୋର୍ଗ୍ରାଉଣ୍ଡ ତଥା ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡକୁ ନେଇପାରିବ। ଆପଣଙ୍କ ବିନା ଅନୁମତିରେ ଆପ୍ଟି ଏହା କରିପାରିବ।"</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"କାର୍ ମୋଡ୍କୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"କାର୍ ମୋଡ୍ ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"ଅନ୍ୟ ଆପ୍ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"ଆପ୍କୁ ଅନ୍ୟ ଆପ୍ର ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଟ ପ୍ରକ୍ରିୟାକୁ ସମାପ୍ତ କରିବାକୁ ଦେଇଥାଏ। ଏହି କାରଣରୁ ଅନ୍ୟ ଆପ୍ଗୁଡ଼ିକ ଚାଲିବା ବନ୍ଦ ହୋଇଯାଇପାରେ।"</string>
+ <!-- no translation found for permlab_systemAlertWindow (7238805243128138690) -->
+ <skip />
+ <!-- no translation found for permdesc_systemAlertWindow (2393776099672266188) -->
+ <skip />
+ <!-- no translation found for permlab_runInBackground (7365290743781858803) -->
+ <skip />
+ <!-- no translation found for permdesc_runInBackground (7370142232209999824) -->
+ <skip />
+ <!-- no translation found for permlab_useDataInBackground (8694951340794341809) -->
+ <skip />
+ <!-- no translation found for permdesc_useDataInBackground (6049514223791806027) -->
+ <skip />
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"ଆପ୍କୁ, ସର୍ବଦା ଚାଲୁଥିବା କରନ୍ତୁ"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"ଆପ୍ଟି ନିଜକୁ ମେମୋରୀରେ ଭାଗ କରିବାକୁ ଦେଇଥାଏ। ଏହାଦ୍ୱାରା ଅନ୍ୟ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ ମେମୋରୀ ଉପଲବ୍ଧକୁ କମ୍ କରିବା ସହ ଟାବ୍ଲେଟ୍ଟିକୁ ମନ୍ଥର କରିବ।"</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"ମେମୋରୀରେ ଆପ୍ଟି ନିଜକୁ ଭାଗ କରିବାକୁ ଦେଇଥାଏ। ଏହା ଟିଭିକୁ ଧୀର କରି ଅନ୍ୟ ଆପ୍ ପାଇଁ ଉପଲବ୍ଧ ମେମୋରୀକୁ ସୀମିତ କରିପାରେ।"</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ଆପ୍ଟି ନିଜକୁ ମେମୋରୀରେ ଭାଗ କରିବାକୁ ଦେଇଥାଏ। ଏହାଦ୍ୱାରା ଅନ୍ୟ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ ମେମୋରୀ ଉପଲବ୍ଧକୁ କମ୍ କରିବା ସହ ଫୋନ୍ଟିକୁ ମନ୍ଥର କରିବ।"</string>
+ <!-- no translation found for permlab_foregroundService (3310786367649133115) -->
+ <skip />
+ <!-- no translation found for permdesc_foregroundService (6471634326171344622) -->
+ <skip />
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"ଆପ୍ ଷ୍ଟୋରେଜ୍ ସ୍ଥାନର ମାପ କରନ୍ତୁ"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"ଆପ୍ର କୋଡ୍, ଡାଟା ଓ କ୍ୟାଶ୍ ଆକାର ହାସଲ କରିବା ପାଇଁ ଏହାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_writeSettings" msgid="2226195290955224730">"ସିଷ୍ଟମ୍ ସେଟିଙ୍ଗ ବଦଳାନ୍ତୁ"</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"ଆପ୍କୁ, ସିଷ୍ଟମର ସେଟିଙ୍ଗ ଡାଟା ବଦଳାଇବାକୁ ଦେଇଥାଏ। ହାନୀକାରକ ଆପ୍ ଦ୍ୱାରା ଆପଣଙ୍କ ସିଷ୍ଟମର କନଫିଗରେସନ୍ ଖରାପ ହୋଇପାରେ।"</string>
+ <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"ଆରମ୍ଭ ହେଲେ ଚଲାନ୍ତୁ"</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"ସିଷ୍ଟମ୍ ବୁଟ୍ ଶେଷ ହେବା କ୍ଷଣି ଆପ୍ଟିକୁ ସ୍ୱତଃ ଆରମ୍ଭ ହେବାକୁ ଦେଇଥାଏ। ଏହା କାରଣରୁ ଟାବଲେଟଟ୍ଟି ଚାଲୁ ହେବାରେ ଅଧିକ ସମୟ ଲାଗିପାରେ ଏବଂ ଆପ୍ଟି ଲଗାତାର ଚାଲିବା ଦ୍ୱାରା ସମଗ୍ର ଟାବଲେଟଟ୍ ମନ୍ଥର ହୋଇଯାଇପାରେ।"</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"ବୁଟିଙ୍ଗ ସମାପ୍ତ ହେବପରେ ଏହି ଆପ୍କୁ ଆରମ୍ଭ ହେବାକୁ ଅନୁମତି ଦେଇଥାଏ। ଏହା TV ଚଳାଇବାକୁ ଅଧିକ ସମୟ ନେଇପାରେ ଏବଂ ଆପ୍କୁ ସବୁବେଳେ ଚାଲିବାରେ ସମଗ୍ର ଟାବଲେଟ୍ ଧୀର କରିପାରେ।"</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"ସିଷ୍ଟମ୍ ବୁଟ୍ ଶେଷ ହେବା କ୍ଷଣି ଆପ୍ଟିକୁ ସ୍ୱତଃ ଆରମ୍ଭ ହେବାକୁ ଦେଇଥାଏ। ଏହା କାରଣରୁ ଫୋନ୍ଟି ଚାଲୁ ହେବାରେ ଅଧିକ ସମୟ ଲାଗିପାରେ ଏବଂ ଆପ୍ଟି ଲଗାତାର ଚାଲିବା ଦ୍ୱାରା ସମଗ୍ର ଫୋନ୍ ମନ୍ଥର ହୋଇଯାଇପାରେ।"</string>
+ <string name="permlab_broadcastSticky" msgid="7919126372606881614">"ଷ୍ଟିକୀ ବ୍ରୋଡକାଷ୍ଟ ପଠାନ୍ତୁ"</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"ଆପ୍କୁ ଷ୍ଟିକୀ ବ୍ରଡ୍କାଷ୍ଟ ପଠାଇବାକୁ ଅନୁମତି ଦେଇଥାଏ, ଯାହା ବ୍ରଡ୍କାଷ୍ଟ ସମାପ୍ତ ହେବାପରେ ବି ରହିଥାଏ। ଅତ୍ୟଧିକ ଉପଯୋଗ ଦ୍ୱାରା ଟାବଲେଟ୍ ମନ୍ଥର ହୋଇପାରେ କିମ୍ବା ଅଧିକ ମେମୋରୀର ବ୍ୟବହାର କରିବା କାରଣରୁ ଏହା ଅସ୍ଥିର ହୋଇପାରେ।"</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"ଷ୍ଟିକୀ ବ୍ରଡ୍କାଷ୍ଟ ପଠାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ, ଯାହା ବ୍ରଡ୍କାଷ୍ଟ ଶେଷ ହେବାପରେ ରହିଥାଏ। ଅତିରିକ୍ତ ବ୍ୟବହାର ଦ୍ୱାରା ଅଧିକ ମେମୋରୀ ବ୍ୟବହାର ହୋଇ ଟିଭିକୁ ଧୀର କିମ୍ବା ଅସ୍ଥିର କରିପାରେ।"</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"ଷ୍ଟିକୀ ବ୍ରଡ୍କାଷ୍ଟ ପଠାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ, ଯାହା ବ୍ରଡ୍କାଷ୍ଟ ଶେଷ ହେବାପରେ ରହିଥାଏ। ଅତିରିକ୍ତ ବ୍ୟବହାର ଦ୍ୱାରା ଅଧିକ ମେମୋରୀ ବ୍ୟବହାର ହୋଇ ଫୋନ୍କୁ ମନ୍ଥର କିମ୍ବା ଅସ୍ଥିର କରିପାରେ।"</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"ଆପଣଙ୍କ ଯୋଗାଯୋଗ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"ଜଣେ ନିର୍ଦ୍ଦିଷ୍ଟ ବ୍ୟକ୍ତିଙ୍କ ସହ ଆପଣ କେତେଥର କଲ୍, ଇମେଲ୍, ତଥା ଯୋଗାଯୋଗ କରିଛନ୍ତି, ତାହାର ନିୟମିତତା ସମେତ ଆପଣଙ୍କ ଟାବଲେଟ୍ରେ ଷ୍ଟୋର୍ ହୋଇଥିବା ଯୋଗାଯୋଗ ବିଷୟରେ ଡାଟା ପଢ଼ିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହ ଅନୁମତି ଦ୍ୱାରା ଆପଣଙ୍କ କଲ୍ ଲଗ୍ ସେଭ୍ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ ତଥା ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ଅଜ୍ଞାତରେ କଲ୍ ଲଗ୍ ଡାଟା ଶେୟାର କରିପାରନ୍ତି।"</string>
+ <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"ଜଣେ ନିର୍ଦ୍ଦିଷ୍ଟ ବ୍ୟକ୍ତିଙ୍କ ସହ ଆପଣ କେତେଥର କଲ୍, ଇମେଲ୍, ତଥା ଯୋଗାଯୋଗ କରିଛନ୍ତି, ତାହାର ନିୟମିତତା ସମେତ ଆପଣଙ୍କ ଟିଭିରେ ଷ୍ଟୋର୍ ହୋଇଥିବା ଯୋଗାଯୋଗ ବିଷୟରେ ଡାଟା ପଢ଼ିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହାର ଅନୁମତି ଦ୍ୱାରା ଆଙ୍ଙକକ କଲ୍ ଲଗ୍ ସେଭ୍ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ ତଥା ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ଅଜ୍ଞାତରେ କଲ୍ ଲଗ୍ ଡାଟା ଶେୟାର କରିପାରନ୍ତି।"</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"ଜଣେ ନିର୍ଦ୍ଦିଷ୍ଟ ବ୍ୟକ୍ତିଙ୍କ ସହ ଆପଣ କେତେ ବ୍ୟବଧାନରେ କଲ୍, ଇମେଲ ତଥା ଯୋଗାଯୋଗ କରିଛନ୍ତି, ସେସବୁ ଅନ୍ତର୍ଭୁକ୍ତ କରି ଆପଣଙ୍କ ଫୋନ୍ରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ଯୋଗାଯୋଗ ବିଷୟରେ ଡାଟା ପଢିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହି ଅନୁମତି ଦ୍ୱାରା ଆପ୍ଟି ଆପଣଙ୍କ ଯୋଗାଯୋଗ ଡାଟା ସେଭ୍ କରିପାରିବ ଏବଂ ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ବିନା ଜ୍ଞାତସାରରେ ଯୋଗାଯୋଗ ଡାଟା ଶେୟାର୍ କରିପାରନ୍ତି।"</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"ନିଜ ଯୋଗାଯୋଗ ସଂଶୋଧନ କରନ୍ତୁ"</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"ଜଣେ ନିର୍ଦ୍ଦିଷ୍ଟ ଯୋଗାଯୋଗଙ୍କ ସହ ଆପଣ କେତେ ବ୍ୟବଧାନରେ କଲ୍, ଇମେଲ ତଥା ଯୋଗାଯୋଗ କରିଛନ୍ତି, ସେସବୁ ଅନ୍ତର୍ଭୁକ୍ତ କରି ଆପଣଙ୍କ ଟାବଲେଟ୍ରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ଯୋଗାଯୋଗ ବିଷୟକ ଡାଟା ବଦଳାଇବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହି ଅନୁମତି ଦ୍ୱାରା ଆପ୍ଟି ଯୋଗାଯୋଗ ଡାଟା ଡିଲିଟ୍ କରିପାରେ।"</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"ଜଣେ ନିର୍ଦ୍ଦିଷ୍ଟ ଯୋଗାଯୋଗଙ୍କ ସହ ଆପଣ କେତେ ବ୍ୟବଧାନରେ କଲ୍, ଇମେଲ ତଥା ଯୋଗାଯୋଗ କରିଛନ୍ତି, ସେସବୁକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରି ଆପଣଙ୍କ ଟିଭିରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ଯୋଗାଯୋଗ ବିଷୟରେ ଡାଟା ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହି ଅନୁମତି ଦ୍ୱାରା ଆପ୍ଟି ଯୋଗାଯୋଗ ଡାଟା ଡିଲିଟ୍ କରିପାରେ।"</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"ଜଣେ ନିର୍ଦ୍ଦିଷ୍ଟ ଯୋଗାଯୋଗଙ୍କ ସହ ଆପଣ କେତେ ବ୍ୟବଧାନରେ କଲ୍, ଇମେଲ ତଥା ଯୋଗାଯୋଗ କରିଛନ୍ତି, ସେସବୁ ଅନ୍ତର୍ଭୁକ୍ତ କରି ଆପଣଙ୍କ ଫୋନ୍ରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ଯୋଗାଯୋଗ ବିଷୟରେ ଡାଟା ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହି ଅନୁମତି ଦ୍ୱାରା ଆପ୍ଟି ଯୋଗାଯୋଗ ଡାଟା ଡିଲିଟ୍ କରିପାରେ।"</string>
+ <string name="permlab_readCallLog" msgid="3478133184624102739">"କଲ୍ ଲଗ୍ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readCallLog" msgid="3204122446463552146">"ଏହି ଆପ୍ ଆପଣଙ୍କ କଲ୍ ହିଷ୍ଟୋରୀ ପଢ଼ିପାରେ।"</string>
+ <string name="permlab_writeCallLog" msgid="8552045664743499354">"କଲ୍ ଲଗ୍ ଲେଖନ୍ତୁ"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"ଇନ୍କମିଙ୍ଗ ତଥା ଆଉଟ୍ଗୋଇଙ୍ଗ କଲ୍ ଡାଟା ସହ ଆପଣଙ୍କ ଟାବ୍ଲେଟ୍ର କଲ୍ ଲଗ୍ ବଦଳାଇବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ କଲ୍ ଲଗ୍ ଲିଭାଇବାକୁ କିମ୍ବା ବଦଳାଇବାକୁ ଏହା ବ୍ୟବହାର କରିପାରନ୍ତି।"</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"ଇନ୍କମିଙ୍ଗ ତଥା ଆଉଟ୍ଗୋଇଙ୍ଗ କଲ୍ ଡାଟା ସହ ଆପଣଙ୍କ ଟିଭିର କଲ୍ ଲଗ୍ ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ କଲ୍ ଲଗ୍ ଲିଭାଇବାକୁ କିମ୍ବା ବଦଳାଇବାକୁ ଏହାକୁ ବ୍ୟବହାର କରିପାରନ୍ତି।"</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"ଇନ୍କମିଙ୍ଗ ତଥା ଆଉଟ୍ଗୋଇଙ୍ଗ କଲ୍ ଡାଟା ସହ ଆପଣଙ୍କ ଫୋନ୍ର କଲ୍ ଲଗ୍ ବଦଳାଇବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ କଲ୍ ଲଗ୍ ଲିଭାଇବାକୁ କିମ୍ବା ବଦଳାଇବାକୁ ଏହା ବ୍ୟବହାର କରିପାରନ୍ତି।"</string>
+ <string name="permlab_bodySensors" msgid="4683341291818520277">"ବଡୀ ସେନ୍ସର୍ ଆକ୍ସେସ୍ କରେ (ଯେପରିକି ହୃଦ୍ ହାର ମନିଟର୍)"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"ଆପ୍କୁ ସେନ୍ସର୍ ଡେଟା ପର୍ଯ୍ୟନ୍ତ ପହଞ୍ଚିବାକୁ ଦେଇଥାଏ, ଯାହା ଆପଣଙ୍କ ଶାରୀରିକ ସ୍ଥିତିର ନିରୀକ୍ଷଣ କରିଥାଏ, ଯେପରିକି ଆପଣଙ୍କ ହୃଦୟ ସ୍ତର।"</string>
+ <!-- no translation found for permlab_readCalendar (6716116972752441641) -->
+ <skip />
+ <!-- no translation found for permdesc_readCalendar (4993979255403945892) -->
+ <skip />
+ <!-- no translation found for permdesc_readCalendar (8837931557573064315) -->
+ <skip />
+ <!-- no translation found for permdesc_readCalendar (4373978642145196715) -->
+ <skip />
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"କ୍ୟାଲେଣ୍ଡର ଇଭେଣ୍ଟରେ ଯୋଡ଼ନ୍ତୁ କିମ୍ବା ସଂଶୋଧନ କରନ୍ତୁ ଏବଂ ମାଲିକଙ୍କ ଅଜାଣତରେ ଅତିଥିମାନଙ୍କୁ ଇମେଲ୍ ପଠାନ୍ତୁ।"</string>
+ <!-- no translation found for permdesc_writeCalendar (1675270619903625982) -->
+ <skip />
+ <!-- no translation found for permdesc_writeCalendar (9017809326268135866) -->
+ <skip />
+ <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ଏହି ଆପ୍, ଆପଣଙ୍କ ଫୋନ୍ରେ କ୍ୟାଲେଣ୍ଡର୍ ଇଭେଣ୍ଟଗୁଡ଼ିକୁ ଯୋଡ଼ିପାରେ, ବାହାର କରିପାରେ କିମ୍ବା ବଦଳାଇପାରେ। କ୍ୟାଲେଣ୍ଡର୍ ମାଲିକଙ୍କ ପାଖରୁ ଆସିଥିବା ପରି ଜଣାପଡ଼ିବା ମେସେଜ୍କୁ ଏହି ଆପ୍ ପଠାଇପାରେ କିମ୍ବା ମାଲିକଙ୍କୁ ନଜଣାଇ ଇଭେଣ୍ଟ ବଦଳାଇପାରେ।"</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ଅତିରିକ୍ତ ଲୋକେଶନ୍ ପ୍ରଦାନକାରୀ କମାଣ୍ଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ଅତିରିକ୍ତ ଲୋକେଶନ୍ ପ୍ରଦାନକାରୀ କମାଣ୍ଡ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। GPS କିମ୍ବା ଅନ୍ୟ ଲୋକେଶନ୍ ସୋର୍ସଗୁଡିକରେ ଆପ୍ଟି ପ୍ରଭାବ ପକାଇପାରେ।"</string>
+ <string name="permlab_accessFineLocation" msgid="251034415460950944">"ନିର୍ଦ୍ଦିଷ୍ଟ ଲୋକେଶନ୍ ଆକ୍ସେସ୍ କରେ (GPS ଏବଂ ନେଟ୍ୱର୍କ-ଆଧାରିତ)"</string>
+ <string name="permdesc_accessFineLocation" msgid="5821994817969957884">"ଏହି ଆପ୍, GPS କିମ୍ୱା ନେଟ୍ୱର୍କ ସୋର୍ସ ଉପରେ ଆଧାର କରି ଆପଣଙ୍କ ଲୋକେଶନ୍ ପ୍ରାପ୍ତ କରିପାରେ, ଯେପରିକି ସେଲ୍ ଟାୱାର୍ ଓ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ। ଏହି ଲୋକେଶନ୍ ସେବା, ଆପଣଙ୍କ ଫୋନ୍ରେ ଅନ୍ ରହିଥିବା ଓ ଉପଲବ୍ଧ ଥିବା ଦରକାର, ଯେଉଁଥିରୁ ଆପ୍ ସେଗୁଡ଼ିକର ବ୍ୟବହାର କରିପାରିବ। ଏହାଦ୍ୱାରା ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ ବଢ଼ିପାରେ।"</string>
+ <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ପାଖାପାଖି ଲୋକେଶନ୍ ଆକ୍ସେସ୍ କରେ (ନେଟ୍ୱର୍କ-ଆଧାରିତ)"</string>
+ <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ଆପଣଙ୍କ ଅଡିଓ ସେଟିଙ୍ଗକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ଆପ୍କୁ ଗ୍ଲୋବାଲ୍ ଅଡିଓ ସେଟିଙ୍ଗ, ଯେପରିକି ଭଲ୍ୟୁମ୍କୁ ସଂଶୋଧିତ କରିବାକୁ ଏବଂ ଆଉଟପୁଟ୍ ପାଇଁ ସ୍ପିକର୍ ବ୍ୟବହାର କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</string>
+ <!-- no translation found for permdesc_recordAudio (4245930455135321433) -->
+ <skip />
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"SIMକୁ କମାଣ୍ଡ ପଠାନ୍ତୁ"</string>
+ <string name="permdesc_sim_communication" msgid="5725159654279639498">"SIMକୁ କମାଣ୍ଡ ପଠାଇବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଏହା ବହୁତ ବିପଦପୂର୍ଣ୍ଣ।"</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"ଫଟୋ ଓ ଭିଡିଓଗୁଡ଼ିକୁ ନିଅନ୍ତୁ"</string>
+ <string name="permdesc_camera" msgid="5392231870049240670">"ଏହି ଆପ୍ ଯେକୌଣସି ସମୟରେ କ୍ୟାମେରା ବ୍ୟବହାର କରି ଫଟୋ ଉଠାଇପାରେ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରେ।"</string>
+ <string name="permlab_vibrate" msgid="7696427026057705834">"କମ୍ପନ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"ଆପ୍କୁ, ଭାଇବ୍ରେଟର୍ ନିୟନ୍ତ୍ରଣ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_callPhone" msgid="3925836347681847954">"ସିଧାସଳଖ ଫୋନ୍ ନମ୍ବରଗୁଡ଼ିକୁ କଲ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"ଆପଣଙ୍କ ହସ୍ତକ୍ଷେପ ବିନା ଫୋନ୍ ନମ୍ଵରକୁ କଲ୍ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଏହାଦ୍ୱାରା ଅପ୍ରତ୍ୟାଶିତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ କିମ୍ବା କଲ୍ ହୋଇପାରେ। ଧ୍ୟାନଦିଅନ୍ତୁ ଯେ, ଏହା ଆପ୍କୁ କୌଣସି ଜରୁରୀକାଳୀନ ନମ୍ବରରେ କଲ୍ କରିବାକୁ ଅନୁମତି ଦିଏନାହିଁ। ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ବିନା ସ୍ୱୀକୃତିରେ କଲ୍ କରି ଆପଣଙ୍କ ପଇସା ଖର୍ଚ୍ଚ କରାଇପାରେ।"</string>
+ <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS କଲ୍ ସେବା ଆକ୍ସେସ୍ କରେ"</string>
+ <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"ଆପଣଙ୍କ ହସ୍ତକ୍ଷେପ ବିନା କଲ୍ କରିପାରିବା ପାଇଁ ଆପ୍କୁ IMS ସେବା ବ୍ୟବହାର କରିବାକୁ ଦିଏ।"</string>
+ <string name="permlab_readPhoneState" msgid="9178228524507610486">"ଫୋନ୍ ସ୍ଥିତି ଓ ପରିଚୟ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ଆପ୍କୁ ଡିଭାଇସ୍ର ଫୋନ୍ ବୈଶିଷ୍ଟ୍ୟ ଆକ୍ସେସ୍ କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ। ଏହି ଅନୁମତି ଆପ୍କୁ ଫୋନ୍ ନମ୍ବର୍ ଓ ଡିଭାଇସ୍ IDଗୁଡ଼ିକୁ ନିର୍ଦ୍ଧାରଣ କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ, କଲ୍ ସକ୍ରିୟ ଥିଲେ ବି ଏବଂ କଲ୍ ଦ୍ୱାରା ସଂଯୋଗ ଥିବା ରିମୋଟ୍ ନମ୍ବର୍କୁ ମଧ୍ୟ।"</string>
+ <!-- no translation found for permlab_manageOwnCalls (1503034913274622244) -->
+ <skip />
+ <!-- no translation found for permdesc_manageOwnCalls (6552974537554717418) -->
+ <skip />
+ <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
+ <skip />
+ <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
+ <skip />
+ <!-- no translation found for permlab_readPhoneNumbers (6108163940932852440) -->
+ <skip />
+ <!-- no translation found for permdesc_readPhoneNumbers (8559488833662272354) -->
+ <skip />
+ <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ଟାବଲେଟ୍କୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍କୁ ଯିବାକୁ ରୋକନ୍ତୁ"</string>
+ <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"ଟିଭିକୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍ରୁ ଯିବାକୁ ରୋକନ୍ତୁ।"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ଫୋନକୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍କୁ ଯିବାକୁ ରୋକନ୍ତୁ"</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ଆପ୍କୁ, ଟାବଲେଟ୍ଟିକୁ ସ୍ଲୀପ୍ ମୋଡ୍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"TVକୁ ଶୁଆଇବାକୁ ଯିବାରୁ ରୋକିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ଆପ୍କୁ, ଫୋନ୍ଟିକୁ ସ୍ଲୀପ୍ ମୋଡ୍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ଇନଫ୍ରାରେଡ୍ ସଂଚାରିତ କରନ୍ତୁ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"ଟାବଲେଟ୍ର ଇନଫ୍ରାରେଡ୍ ଟ୍ରାନ୍ସମିଟର୍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"ଟିଭିର ଇନ୍ଫ୍ରାରେଡ୍ ଟ୍ରାନ୍ସମିଟର୍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"ଫୋନ୍ର ଇନଫ୍ରାରେଡ୍ ଟ୍ରାନ୍ସମିଟର୍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_setWallpaper" msgid="6627192333373465143">"ୱାଲପେପର୍ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"ଆପ୍କୁ, ସିଷ୍ଟମ୍ ୱାଲପେପର୍ ସେଟ୍ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ଆପଣଙ୍କ ୱାଲ୍ପେପର୍ର ଆକାର ଆଡ୍ଜଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"ଆପ୍କୁ, ସିଷ୍ଟମ୍ ୱାଲପେପର୍ ଆକାରର ସୂଚନା ସେଟ୍ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_setTimeZone" msgid="2945079801013077340">"ଟାଇମ୍ ଜୋନ୍ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"ଆପ୍କୁ, ଟାବଲେଟ୍ର ଟାଇମ୍ ଜୋନ୍ ବଦଳାଇବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"ଟିଭିର ସଂଯୋଗ ପ୍ରବନ୍ଧିତ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"ଆପ୍କୁ, ଫୋନ୍ର ଟାଇମ୍ ଜୋନ୍ ବଦଳାଇବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_getAccounts" msgid="1086795467760122114">"ଡିଭାଇସ୍ରେ ଆକାଉଣ୍ଟ ଖୋଜନ୍ତୁ"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"ଟାବଲେଟ୍ ଦ୍ୱାରା ପରିଚିତ ଆକାଉଣ୍ଟର ତାଲିକା ପ୍ରାପ୍ତ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଆପଣ ଇନଷ୍ଟଲ୍ କରିଥିବା ଆପ୍ଲିକେଶନ୍ ଦ୍ୱାରା ତିଆରି କରାଯାଇଥିବା କୌଣସି ଆକାଉଣ୍ଟ ବି ଏଥିରେ ସାମିଲ୍ ହୋଇପାରେ।"</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"TV ଦ୍ୱାରା ପରିଚିତ ଆକାଉଣ୍ଟର ତାଲିକା ପ୍ରାପ୍ତ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଫଳରେ ଆପଣଙ୍କ ଦ୍ୱାରା ଇନଷ୍ଟଲ୍ କରାଯାଇଥିବା ଅନୁପ୍ରୟୋଗରେ ଖୋଲାଯାଇଥିବା କୌଣସି ବି ଆକାଉଣ୍ଟରେ ସାମିଲ୍ ହୋଇପାରିବ।"</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"ଫୋନ୍ ଦ୍ୱାରା ପରିଚିତ ଆକାଉଣ୍ଟର ତାଲିକା ପ୍ରାପ୍ତ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ଆପଣ ଇନଷ୍ଟଲ୍ କରିଥିବା ଆପ୍ଲିକେଶନ୍ ଦ୍ୱାରା ତିଆରି କରାଯାଇଥିବା କୌଣସି ଆକାଉଣ୍ଟ ବି ଏଥିରେ ସାମିଲ୍ ହୋଇପାରେ।"</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"ନେଟ୍ୱର୍କ ସଂଯୋଗ ଦେଖନ୍ତୁ"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"କେଉଁ ନେଟ୍ୱର୍କ ଉପସ୍ଥିତ ତଥା ସଂଯୁକ୍ତ ଅଛି, ତାହା ବିଷୟରେ ସୂଚନା ଦେଖିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"ପୂର୍ଣ୍ଣ ନେଟ୍ୱର୍କ ଆକ୍ସେସ୍ ରହିଛି"</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"ଆପ୍କୁ ନେଟ୍ୱର୍କ ସକେଟ୍ ବନେଇବା ଏବଂ କଷ୍ଟମ୍ ନେଟ୍ୱର୍କ ପ୍ରୋଟୋକଲ ବ୍ୟବହାର କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ। ବ୍ରାଉଜର୍ ଏବଂ ଅନ୍ୟ ଆପ୍ଲିକେଶନ୍ ଦ୍ୱାରା ଇଣ୍ଟରନେଟ୍କୁ ଡାଟା ପଠାଯାଇପାରେ, ତେଣୁ ଏହି ଅନୁମତି ଇଣ୍ଟରନେଟ୍କୁ ଡାଟା ପଠେଇବା ପାଇଁ ଆବଶ୍ୟକ ହୁଏନାହିଁ।"</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"ନେଟୱର୍କ ସଂଯୋଗକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"ନେଟୱର୍କ ସଂଯୋଗର ସ୍ଥିତି ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_changeTetherState" msgid="5952584964373017960">"ଟିଥର୍ ହୋଇଥିବା କନେକ୍ଟିଭିଟୀକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"ଟିଥର୍ ହୋଇଥିବା ନେଟୱର୍କ ସଂଯୋଗର ସ୍ଥିତି ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"ୱାଇ-ଫାଇ ସଂଯୋଗ ଦେଖନ୍ତୁ"</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"ୱାଇ-ଫାଇ ନେଟୱର୍କିଙ୍ଗ ବିଷୟରେ ସୂଚନା ଦେଖିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ, ଯେପରିକି ୱାଇ-ଫାଇ ସକ୍ଷମ ହୋଇଛି କି ନାହିଁ ଏବଂ ସଂଯୁକ୍ତ ହୋଇଥିବା ୱାଇ-ଫାଇ ଡିଭାଇସ୍ର ନାମ।"</string>
+ <string name="permlab_changeWifiState" msgid="6550641188749128035">"ୱାଇ-ଫାଇରୁ ସଂଯୋଗ ଓ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"ଆପ୍କୁ ୱାଇ-ଫାଇ ଆକ୍ସେସ୍ ପଏଣ୍ଟ ସହିତ ସଂଯୋଗ ଓ ବିଚ୍ଛିନ୍ନ କରିବାକୁ ତଥା ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ ପାଇଁ ଡିଭାଇସ୍ କନଫିଗରେଶନ୍ରେ ପରିବର୍ତ୍ତନ କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"ୱାଇ-ଫାଇ ମଲ୍ଟିକାଷ୍ଟ ରିସେପଶନ ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"କେବଳ ଆପଣଙ୍କ ଟାବ୍ଲେଟ୍ ନୁହେଁ, ବରଂ ମଲ୍ଟିକାଷ୍ଟ ଠିକଣାଗୁଡ଼ିକ ବ୍ୟବହାର କରି ଏକ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କରେ ଥିବା ସମସ୍ତ ଡିଭାଇସ୍କୁ ପଠାଯିବା ପ୍ୟାକେଟ୍ଗୁଡ଼ିକ ପ୍ରାପ୍ତ କରିବାକୁ ଆପ୍ଟି ଅନୁମତି ଦେଇଥାଏ। ଅଣ-ମଲ୍ଟିକାଷ୍ଟ ମୋଡ୍ ତୁଳନାରେ ଏହା ଅଧିକ ପାୱାର୍ ବ୍ୟବହାର କରେ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"କେବଳ ଆପଣଙ୍କ ଟିଭି ନୁହେଁ, ମଲ୍ଟିକାଷ୍ଟ ଠିକଣା ବ୍ୟବହାର କରି ଏକ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କରେ ସମସ୍ତ ଡିଭାଇସ୍କୁ ପଠାଯାଇଥିବା ପ୍ୟାକେଟ୍ ପ୍ରାପ୍ତ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଅଣ-ମଲ୍ଟିକାଷ୍ଟ ମୋଡ୍ ତୁଳନାରେ ଏହା ଅଧିକ ପାୱାର୍ ବ୍ୟବହାର କରେ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"କେବଳ ଆପଣଙ୍କ ଫୋନ୍ ନୁହେଁ, ବରଂ ମଲ୍ଟିକାଷ୍ଟ ଠିକଣାଗୁଡ଼ିକ ବ୍ୟବହାର କରି ଏକ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କରେ ଥିବା ସମସ୍ତ ଡିଭାଇସ୍କୁ ପଠାଯିବା ପ୍ୟାକେଟ୍ଗୁଡ଼ିକ ପ୍ରାପ୍ତ କରିବାକୁ ଆପ୍ଟି ଅନୁମତି ଦେଇଥାଏ। ଅଣ-ମଲ୍ଟିକାଷ୍ଟ ମୋଡ୍ ତୁଳନାରେ ଏହା ଅଧିକ ପାୱାର୍ ବ୍ୟବହାର କରେ।"</string>
+ <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"ବ୍ଲୁ-ଟୁଥ୍ ସେଟିଙ୍ଗ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"ସ୍ଥାନୀୟ ବ୍ଲୁ-ଟୁଥ, ଟାବଲେଟ୍କୁ କନଫିଗର୍ କରିବାକୁ ଏବଂ ରିମୋର୍ଟ ଡିଭାଇସ୍କୁ ଚିହ୍ନାଇବା ତଥା ସେଗୁଡ଼ିକୁ ପେୟାର୍ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"ଆପ୍କୁ ସ୍ଥାନୀୟ ବ୍ଲୁ-ଟୁଥ୍ TVକୁ କନଫିଗର୍ କରିବାକୁ ଦେଇଥାଏ ଏବଂ ରିମୋର୍ଟ ଡିଭାଇସ୍କୁ ଚିହ୍ନାଇ ସେମାନଙ୍କୁ ଯୋଡ଼ିଥାଏ।"</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"ସ୍ଥାନୀୟ ବ୍ଲୁ-ଟୁଥ, ଫୋନ୍କୁ କନଫିଗର୍ କରିବାକୁ ଏବଂ ରିମୋର୍ଟ ଡିଭାଇସ୍କୁ ଚିହ୍ନାଇବା ତଥା ସେଗୁଡ଼ିକୁ ପେୟାର୍ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX ସହିତ ସଂଯୋଗ ଏବଂ ଏଥିରୁ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"WiMAX ସକ୍ଷମ କି ନାହିଁ ସ୍ଥିର କରିବାକୁ ଏବଂ ସଂଯୁକ୍ତ ଥିବା କୌଣସି WiMAX ନେଟ୍ୱର୍କ ବିଷୟରେ ସୂଚନା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ ।"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX ସ୍ଥିତିକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"WiMAX ନେଟ୍ୱର୍କରୁ ଟାବଲେଟ୍ ସଂଯୋଗ କରିବାକୁ ଏବଂ ବିଚ୍ଛିନ୍ନ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"ଟିଭିକୁ ସଂଯୋଗ କରିବାକୁ ତଥା WiMAX ନେଟ୍ୱର୍କରୁ ଟିଭିକୁ ବିଚ୍ଛିନ୍ନ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"WiMAX ନେଟ୍ୱର୍କରୁ ଫୋନ୍ ସଂଯୋଗ କରିବାକୁ ଏବଂ ବିଚ୍ଛିନ୍ନ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"ବ୍ଲୁ-ଟୁଥ୍ ଡିଭାଇସ୍ ଦେଖନ୍ତୁ"</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ଟାବଲେଟ୍ରେ ଥିବା ବ୍ଲୁ-ଟୁଥ୍ର କନଫିଗରେଶନ୍ ଦେଖିବାକୁ ଏବଂ ପେୟାର୍ କରାଯାଇଥିବା ଡିଭାଇସ୍ ସହିତ ସଂଯୋଗ ସ୍ୱୀକାର କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"ଟିଭିରେ ବ୍ଲୁ-ଟୁଥ୍ର କନଫିଗରେଶନ୍ ଦେଖିବାକୁ ଏବଂ ପେୟାର୍ ହୋଇଥିବା ଡିଭାଇସ୍ ସହ ସଂଯୋଗ ତିଆରି ତଥା ସ୍ୱୀକାର କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ଫୋନ୍ରେ ଥିବା ବ୍ଲୁ-ଟୁଥ୍ର କନଫିଗରେଶନ୍ ଦେଖିବାକୁ ଏବଂ ପେୟାର୍ କରାଯାଇଥିବା ଡିଭାଇସ୍ ସହିତ ସଂଯୋଗ ସ୍ୱୀକାର କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"ନିଅର୍ ଫିଲ୍ଡ କମ୍ୟୁନିକେଶନ୍ ଉପରେ ନିୟନ୍ତ୍ରଣ ରଖନ୍ତୁ"</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"ନିଅର୍ ଫିଲ୍ଡ କମ୍ୟୁନିକେସନ୍ନ (NFC) ଟାଗ୍, କାର୍ଡ ଓ ରିଡରଗୁଡ଼ିକ ସହ ଯୋଗାଯୋଗ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ ଲକ୍ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ଆପ୍କୁ କୀ\'ଲକ୍ କିମ୍ବା ସେଥିରେ ଥିବା କୌଣସି ପାସ୍ୱର୍ଡ ସୁରକ୍ଷାକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଅନୁମତି ଦିଏ, ଉଦାହରଣସ୍ୱରୂପ, ଇନ୍କମିଙ୍ଗ ଫୋନ୍ କଲ୍ ପ୍ରାପ୍ତ କରିବା ସମୟରେ ଫୋନ୍ଟି କୀ\'ଲକ୍କୁ ଅକ୍ଷମ କରିଦିଏ, ତା’ପରେ କଲ୍ ସମାପ୍ତ ହେବାପରେ ପୁଣି କୀ\'ଲକ୍କୁ ସକ୍ଷମ କରିଥାଏ।"</string>
+ <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ବ୍ୟବହାର କରିବା ପାଇଁ ଆଙ୍ଗୁଠି ଚିହ୍ନ ଯୋଡ଼ିବାକୁ ଓ ଡିଲିଟ୍ କରିବାକୁ ଆପକୁ ବିଧି ଆରମ୍ଭ କରିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_useFingerprint" msgid="3150478619915124905">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ସ୍ୱୀକୃତି ପାଇଁ ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରିବାକୁ ଅନୁମତି ଦିଏ"</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଂଶିକ ଚିହ୍ନଟ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରୋସେସ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନ୍ସର୍ ମଇଳା ହୋଇଯାଇଛି। ଦୟାକରି ସଫା କରନ୍ତୁ ଓ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"ଆଙ୍ଗୁଠି ବହୁତ ଜୋର୍ରେ ଚଲାଗଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ଆଙ୍ଗୁଠି ଖୁବ୍ ଧୀରେ ନିଆଗଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string-array name="fingerprint_acquired_vendor">
+ </string-array>
+ <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string>
+ <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
+ <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଷ୍ଟୋର୍ କରାଯାଇପାରିବ ନାହିଁ। ଦୟାକରି ପୂର୍ବରୁ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନକୁ ବାହାର କରିଦିଅନ୍ତୁ।"</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"ଆଙ୍ଗୁଠି ଚିହ୍ନର ସମୟ ଶେଷ ହେଲା । ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="fingerprint_error_canceled" msgid="4402024612660774395">"ଆଙ୍ଗୁଠି ଚିହ୍ନ କାର୍ଯ୍ୟ କ୍ୟାନ୍ସଲ୍ କରାଗଲା।"</string>
+ <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
+ <skip />
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"ବହୁତ ପ୍ରୟାସ କରାଗଲା। ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
+ <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <!-- no translation found for fingerprint_error_no_fingerprints (7654382120628334248) -->
+ <skip />
+ <!-- no translation found for fingerprint_error_hw_not_present (5729436878065119329) -->
+ <skip />
+ <string name="fingerprint_name_template" msgid="5870957565512716938">"ଆଙ୍ଗୁଠି <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string-array name="fingerprint_error_vendor">
+ </string-array>
+ <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଇକନ୍"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ସିଙ୍କ ସେଟିଙ୍ଗକୁ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ଏକ ଆକାଉଣ୍ଟ ପାଇଁ ସିଙ୍କ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ୍ଟିକୁ ଅନୁମତି ଦିଏ। ଉଦାହରଣସ୍ୱରୂପ, ଲୋକଙ୍କ ଆପ୍ ଏକ ଆକାଉଣ୍ଟରେ ସିଙ୍କ ହୋଇଛି କି ନାହିଁ ଏହା ଜାଣିପାରେ।"</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ସିଙ୍କ ଅନ୍ ଓ ଅଫ୍ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"ଆପ୍କୁ ଏକ ଆକାଉଣ୍ଟ ପାଇଁ ସିଙ୍କ ସେଟିଙ୍ଗ ସଂଶୋଧନ କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ। ଉଦାହରଣସ୍ୱରୂପ, ଏହାର ବ୍ୟବହାର କୌଣସି ଆକାଉଣ୍ଟରେ ଥିବା ଲୋକଙ୍କ ଆପ୍ ସହିତ ସିଙ୍କ କରିବାକୁ ସକ୍ଷମ ହୋଇଥାଏ।"</string>
+ <string name="permlab_readSyncStats" msgid="7396577451360202448">"ସିଙ୍କ୍ ପରିସଂଖ୍ୟାନକୁ ପଢ଼ନ୍ତୁ।"</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"ସିଙ୍କ କାର୍ଯ୍ୟର ହିଷ୍ଟୋରୀ ତଥା କେତେ ଡାଟା ସିଙ୍କ କରାଯାଇଛି, ସେଗୁଡ଼ିକ ଅନ୍ତର୍ଭୁକ୍ତ କରି, ଏକ ଆକାଉଣ୍ଟର ସିଙ୍କ ଅବସ୍ଥା ପଢ଼ିବା ପାଇଁ ଗୋଟିଏ ଆପ୍କୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"ନିଜ USB ଷ୍ଟୋରେଜ୍ର କଣ୍ଟେଣ୍ଟ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"ନିଜ SD କାର୍ଡର କଣ୍ଟେଣ୍ଟ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"USB ଷ୍ଟୋରେଜ୍ରେ ଥିବା କଣ୍ଟେଣ୍ଟ ପଢିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"ଆପଣଙ୍କ SD କାର୍ଡରେ ଥିବା କଣ୍ଟେଣ୍ଟ ପଢ଼ିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"ଆପଣଙ୍କ USB ଷ୍ଟୋରେଜ୍ର କଣ୍ଟେଣ୍ଟ ସଂଶୋଧନ କରନ୍ତୁ କିମ୍ବା ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"ନିଜ SD କାର୍ଡର କଣ୍ଟେଣ୍ଟ ସଂଶୋଧନ କିମ୍ବା ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"ଆପ୍କୁ USB ଷ୍ଟୋରେଜରେ ଲେଖିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"ଆପ୍କୁ SD କାର୍ଡରେ ଲେଖିବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_use_sip" msgid="2052499390128979920">"SIP କଲ୍ କରନ୍ତୁ ଏବଂ ଗ୍ରହଣ କରନ୍ତୁ"</string>
+ <string name="permdesc_use_sip" msgid="2297804849860225257">"ଆପ୍କୁ SIP କଲ୍ କରିବାକୁ ଏବଂ ପାଇବାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"ନୂତନ ଦୂରସଂଚାର ସିମ୍ ସଂଯୋଗ ନଥିଭୁକ୍ତ କରନ୍ତୁ"</string>
+ <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"ନୂତନ ଦୂରସଂଚାର ସିମ୍ ସଂଯୋଗକୁ ନଥିଭୁକ୍ତ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permlab_register_call_provider" msgid="108102120289029841">"ନୂତନ ଦୂରସଂଚାର ସଂଯୋଗ ନଥିଭୁକ୍ତ କରନ୍ତୁ"</string>
+ <string name="permdesc_register_call_provider" msgid="7034310263521081388">"ନୂତନ ଦୂରସଂଚାର ସଂଯୋଗକୁ ନଥିଭୁକ୍ତ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permlab_connection_manager" msgid="1116193254522105375">"ଟେଲିକମ୍ ସଂଯୋଗ ପରିଚାଳିତ କରନ୍ତୁ"</string>
+ <string name="permdesc_connection_manager" msgid="5925480810356483565">"ଦୁରସଂଚାର ସଂଯୋଗ ପ୍ରବନ୍ଧିତ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permlab_bind_incall_service" msgid="6773648341975287125">"ଇନ୍ କଲ୍ ସ୍କ୍ରୀନ୍ ସହିତ ସଂଯୋଗ କରନ୍ତୁ"</string>
+ <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"ୟୁଜର୍ କଲ୍ ଇନ୍ ସ୍କ୍ରୀନ୍ କେବେ ଓ କିପରି ଦେଖୁଛି, ତାହାକୁ ନିୟନ୍ତ୍ରିତ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permlab_bind_connection_service" msgid="3557341439297014940">"ଟେଲିଫୋନୀ ସେବା ସହିତ ସଂଯୋଗ କରନ୍ତୁ"</string>
+ <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"ଆପ୍କୁ କଲ୍ କରିବା ଏବଂ ପ୍ରାପ୍ତ କରିବା ପାଇଁ ଟେଲିଫୋନୀ ସେବା ସହିତ ସଂଯୋଗ କରିବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permlab_control_incall_experience" msgid="9061024437607777619">"ଏକ କଲ୍ ୟୁଜର୍ ଅନୁଭବ ପ୍ରଦାନ କରିଥାଏ"</string>
+ <string name="permdesc_control_incall_experience" msgid="915159066039828124">"ଆପ୍କୁ ଇନ୍-କ୍ଲଲ୍ ୟୁଜର୍ ଅନୁଭବ ନେବାକୁ ଦେଇଥାଏ।"</string>
+ <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"ଐତିହାସିକ ନେଟୱର୍କ ଉପଯୋଗ ବିଷୟରେ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"ନିର୍ଦ୍ଦିଷ୍ଟ ନେଟୱର୍କ ତଥା ଆପ୍ଗୁଡ଼ିକ ପାଇଁ ବିଗତ ଦିନର ନେଟୱର୍କ ବ୍ୟବହାର ପଢ଼ିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"ନେଟ୍ୱର୍କ ପଲିସୀକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"ନେଟୱର୍କ ପଲିସୀ ପରିଚାଳନା କରିବାକୁ ଏବଂ ଆପ୍-ନିର୍ଦ୍ଦିଷ୍ଟ ନିୟମ ଧାର୍ଯ୍ୟ କରିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ନେଟ୍ୱର୍କ ବ୍ୟବହାର ଗଣନାକୁ ସଂଶୋଧନ କରନ୍ତୁ"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ଆପ୍ ପାଇଁ କିପରି ନେଟ୍ୱର୍କ ବ୍ୟବହାର ଗଣନା କରାଯିବ, ସେଥିରେ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ସାମାନ୍ୟ ଆପ୍ ଦ୍ୱାରା ବ୍ୟବହାର କରାଯିବା ପାଇଁ ନୁହେଁ।"</string>
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ଅନ୍ୟ ଆପ୍ଲିକେଶନ୍ ଦ୍ୱାରା ପୋଷ୍ଟ କରାଯାଇଥିବାକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରି ବିଜ୍ଞପ୍ତିକୁ ହାସଲ, ପରୀକ୍ଷା, ତଥା ଖାଲି କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ଏକ ବିଜ୍ଞପ୍ତି ଶ୍ରୋତା ସେବା ସହିତ ଯୋଡ଼ିହୁଅନ୍ତୁ"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ଶ୍ରୋତା ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟରଫେସ୍କୁ ବାନ୍ଧିରଖିବା ପଇଁ ଧାରକକୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବ ନାହିଁ।"</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ଏକ ସର୍ତ୍ତାବଳୀ ପ୍ରଦାନକାରୀ ସେବା ସହିତ ଯୋଡ଼ିହୁଅନ୍ତୁ"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ଏକ ସ୍ଥିତି ପ୍ରଦାନକାରୀ ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟରଫେସ୍ ବାନ୍ଧିରଖିବାକୁ ଧାରକକୁ ଅନୁମତି ଦେଇଥାଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବନାହିଁ।"</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"ଏକ ଡ୍ରୀମ୍ ସେବା ସହିତ ଯୋଡ଼ିହୁଅନ୍ତୁ"</string>
+ <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ଏକ ଡ୍ରୀମ୍ ସେବାର ଶୀର୍ଷ-ସ୍ତର ଇଣ୍ଟରଫେସ୍କୁ ବାନ୍ଧିରଖିବା ପାଇଁ ଧାରକକୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବନାହିଁ।"</string>
+ <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"କେରିଅରଙ୍କ ଦ୍ୱାରା ଦିଆଯାଇଥିବା କନଫିଗରେଶନ୍ ଆପ୍ ଆରମ୍ଭ କରନ୍ତୁ"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"କେରିଅର୍ ଦ୍ୱାରା ଦିଆଯାଇଥିବା କନଫିଗରେଶନ୍ ଆପ୍ ରଖିବାକୁ ଧାରକକୁ ଅନୁମତି ଦେଇଥାଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବନାହିଁ।"</string>
+ <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ନେଟ୍ୱର୍କ ସ୍ଥିତିର ନୀରିକ୍ଷଣକୁ ଶୁଣନ୍ତୁ"</string>
+ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ନେଟ୍ୱର୍କ ସ୍ଥିତିରେ ନୀରିକ୍ଷଣ କରିବା ପାଇଁ ଗୋଟିଏ ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବ ନାହିଁ।"</string>
+ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ଇନପୁଟ୍ ଡିଭାଇସ୍ କାଲିବରେଶନ୍ ବଦଳାନ୍ତୁ"</string>
+ <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ଟଚ୍ ସ୍କ୍ରୀନ୍ର କାଲିବରେଶନ୍ ପାରାମିଟର୍ ସଂଶୋଧନ କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବନାହିଁ।"</string>
+ <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM ସର୍ଟିଫିକେଟ୍ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM ସର୍ଟିଫିକେଟ୍ର ପ୍ରାବଧାନ ତଥା ବ୍ୟବହାର କରିବା ପାଇଁ ଏକ ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବନାହିଁ।"</string>
+ <string name="permlab_handoverStatus" msgid="7820353257219300883">"Android ବିମ୍ ଟ୍ରାନ୍ସଫର୍ ଷ୍ଟାଟସ୍ ପ୍ରାପ୍ତ କରେ"</string>
+ <string name="permdesc_handoverStatus" msgid="4788144087245714948">"କିଛି ସମୟ ପୂର୍ବରୁ ହୋଇଥିବା Android ବିମ୍ ଟ୍ରାନ୍ସଫର୍ ବିଷୟରେ ସୂଚନା ପ୍ରାପ୍ତ କରିବାକୁ ଏହି ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦେଇଥାଏ"</string>
+ <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"DRM ସର୍ଟିଫିକେଟ୍ ଅପସାରଣ କରନ୍ତୁ"</string>
+ <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM ସାର୍ଟିଫିକେଟ୍ କୁ ହଟାଇବା ପାଇଁ ଏକ ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହେବନାହିଁ।"</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ଏକ କେରିଅର୍ ମେସେଜିଙ୍ଗ ସେବା ସହିତ ଯୋଡ଼ିହୁଅନ୍ତୁ"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ଏକ କେରିଅର୍ ମେସେଜିଙ୍ଗ ସେବାର ଶୀର୍ଷ-ସ୍ତରୀୟ ଇଣ୍ଟରଫେସ୍ ବାନ୍ଧିରଖିବାକୁ ହୋଲ୍ଡରଙ୍କୁ ଅନୁମତି ଦିଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ ଆବଶ୍ୟକ କରାଯିବା ଉଚିତ ନୁହେଁ।"</string>
+ <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"କେରିଅର୍ ସେବାଗୁଡ଼ିକ ସହ ଯୋଡ଼ି ହୁଅନ୍ତୁ"</string>
+ <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"କେରିଅର୍ ସେବାଗୁଡ଼ିକ ସହିତ ଧାରକଙ୍କୁ ଯୋଡ଼ିଥାଏ। ସାମାନ୍ୟ ଆପ୍ ପାଇଁ କଦାପି ଆବଶ୍ୟକ ହୁଏନାହିଁ।"</string>
+ <string name="permlab_access_notification_policy" msgid="4247510821662059671">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" କନଫିଗରେଶନ୍ ପଢ଼ିବା ତଥା ଲେଖିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"ପାସ୍ୱର୍ଡ ନିୟମାବଳୀ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="policydesc_limitPassword" msgid="2502021457917874968">"ଲକ୍ ସ୍କ୍ରୀନ୍ ପାସ୍ୱର୍ଡ ଓ PINରେ ଅନୁମୋଦିତ ଦୀର୍ଘତା ଓ ବର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
+ <!-- no translation found for policylab_watchLogin (5091404125971980158) -->
+ <skip />
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରିଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଟାବଲେଟ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଟାବଲେଟ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ସ୍କ୍ରିନକୁ ଅନଲକ୍ କରିବା ସମୟରେ ଟାଇପ୍ କରିଥିବା ଭୁଲ ପାସ୍ୱର୍ଡ ସଂଖ୍ୟା ଉପରେ ନୀରିକ୍ଷଣ ରଖନ୍ତୁ ଏବଂ ଟିଭି ଲକ୍ କରନ୍ତୁ ଓ ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱର୍ଡ ଟାଇପ୍ କରାଯାଇଛି, ତେବେ ସମସ୍ତ ଟିଭି ଡାଟାକୁ ହଟାଇଦିଅନ୍ତୁ।"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରିଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଫୋନ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଫୋନ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଟାବଲେଟ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଟିଭିକୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଫୋନ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
+ <string name="policylab_resetPassword" msgid="4934707632423915395">"ସ୍କ୍ରୀନ୍ ଲକ୍ ବଦଳାନ୍ତୁ"</string>
+ <string name="policydesc_resetPassword" msgid="1278323891710619128">"ସ୍କ୍ରୀନ୍ ଲକ୍ ବଦଳାନ୍ତୁ।"</string>
+ <string name="policylab_forceLock" msgid="2274085384704248431">"ସ୍କ୍ରୀନ୍କୁ ଲକ୍ କରନ୍ତୁ"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"ସ୍କ୍ରୀନ୍ କିପରି ଓ କେତେବେଳେ ଲକ୍ କରାଯିବ, ତାହା ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"ସମସ୍ତ ଡାଟା ଖାଲି କରନ୍ତୁ"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ସେଟିଙ୍ଗ କରାଇ ଟାବ୍ଲେଟ୍ର ଡାଟା ଲିଭାଇଥାଏ।"</string>
+ <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ସେଟିଙ୍ଗ କରାଇ ଟିଭିର ଡାଟା ଲିଭାଇଥାଏ।"</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ସେଟିଙ୍ଗ କରାଇ ଫୋନ୍ର ଡାଟା ଲିଭାଇଥାଏ।"</string>
+ <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ୟୁଜର୍ ଡାଟା ଲିଭାନ୍ତୁ"</string>
+ <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ବିନା ଚେତାବନୀରେ ଏହି ଟାବଲେଟରେ ଥିବା ଏହି ୟୁଜରଙ୍କ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>
+ <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ବିନା ଚେତାବନୀରେ ଏହି ଟିଭିରେ ଥିବା ଏହି ୟୁଜରଙ୍କ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>
+ <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"ବିନା ଚେତାବନୀରେ ଏହି ଫୋନରେ ଥିବା ଏହି ୟୁଜରଙ୍କ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>
+ <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ଗ୍ଲୋବଲ୍ ପ୍ରକ୍ସୀ ଡିଭାଇସ୍କୁ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ପଲିସୀ ସକ୍ଷମ କରାଯାଇଥିବାବେଳେ ବ୍ୟବହାର କରିବା ପାଇଁ ଗ୍ଲୋବାଲ୍ ପ୍ରକ୍ସୀ ସେଟ୍ କରନ୍ତୁ। କେବଳ ଡିଭାଇସ୍ ମାଲିକ ଗ୍ଲୋବାଲ୍ ପ୍ରକ୍ସୀ ସେଟ୍ କରିପାରିବେ।"</string>
+ <string name="policylab_expirePassword" msgid="5610055012328825874">"ସ୍କ୍ରୀନ୍ ଲକ୍ ପାସ୍ୱର୍ଡର ସମୟ ସମାପ୍ତି ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"ସ୍କ୍ରୀନ୍ ଲକ୍ ପାସ୍ୱର୍ଡ, PIN କିମ୍ବା ପାଟର୍ନ କେତେ ବ୍ୟବଧାନରେ ପରିବର୍ତ୍ତନ କରିବାକୁ ହେବ, ତାହା ପରିବର୍ତ୍ତନ କରନ୍ତୁ।"</string>
+ <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ଷ୍ଟୋରେଜ୍ ଏନକ୍ରିପସନ୍କୁ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ଷ୍ଟୋର୍ କରାଯାଇଥିବା ଡାଟା ଏନ୍କ୍ରେପ୍ଟ କରିବା ଆବଶ୍ୟକ।"</string>
+ <string name="policylab_disableCamera" msgid="6395301023152297826">"କ୍ୟାମେରାଗୁଡ଼ିକୁ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"ସମସ୍ତ ଡିଭାଇସ୍ର କ୍ୟାମେରା ବ୍ୟବହାର କରିବା ପ୍ରତିରୋଧ କରନ୍ତୁ।"</string>
+ <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"କିଛି ସ୍କ୍ରୀନ୍ ଲକ୍ ସୁବିଧାକୁ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"କିଛି ସ୍କ୍ରୀନ୍ ଲକ୍ ସୁବିଧା ବ୍ୟବହାର କରିବାରେ ପ୍ରତିରୋଧ କରନ୍ତୁ।"</string>
+ <string-array name="phoneTypes">
+ <item msgid="8901098336658710359">"ହୋମ୍"</item>
+ <item msgid="869923650527136615">"ମୋବାଇଲ୍"</item>
+ <item msgid="7897544654242874543">"ୱାର୍କ"</item>
+ <item msgid="1103601433382158155">"ୱାର୍କ ଫ୍ୟାକ୍ସ"</item>
+ <item msgid="1735177144948329370">"ହୋମ୍ ଫାକ୍ସ"</item>
+ <item msgid="603878674477207394">"ପେଜର୍"</item>
+ <item msgid="1650824275177931637">"ଅନ୍ୟାନ୍ୟ"</item>
+ <item msgid="9192514806975898961">"କଷ୍ଟମ୍"</item>
+ </string-array>
+ <string-array name="emailAddressTypes">
+ <item msgid="8073994352956129127">"ହୋମ୍"</item>
+ <item msgid="7084237356602625604">"ୱାର୍କ"</item>
+ <item msgid="1112044410659011023">"ଅନ୍ୟାନ୍ୟ"</item>
+ <item msgid="2374913952870110618">"କଷ୍ଟମ୍"</item>
+ </string-array>
+ <string-array name="postalAddressTypes">
+ <item msgid="6880257626740047286">"ହୋମ୍"</item>
+ <item msgid="5629153956045109251">"ୱାର୍କ"</item>
+ <item msgid="4966604264500343469">"ଅନ୍ୟାନ୍ୟ"</item>
+ <item msgid="4932682847595299369">"କଷ୍ଟମ୍"</item>
+ </string-array>
+ <string-array name="imAddressTypes">
+ <item msgid="1738585194601476694">"ହୋମ୍"</item>
+ <item msgid="1359644565647383708">"ୱାର୍କ"</item>
+ <item msgid="7868549401053615677">"ଅନ୍ୟାନ୍ୟ"</item>
+ <item msgid="3145118944639869809">"କଷ୍ଟମ୍"</item>
+ </string-array>
+ <string-array name="organizationTypes">
+ <item msgid="7546335612189115615">"ୱାର୍କ"</item>
+ <item msgid="4378074129049520373">"ଅନ୍ୟାନ୍ୟ"</item>
+ <item msgid="3455047468583965104">"କଷ୍ଟମ୍"</item>
+ </string-array>
+ <string-array name="imProtocols">
+ <item msgid="8595261363518459565">"AIM"</item>
+ <item msgid="7390473628275490700">"Windows Live"</item>
+ <item msgid="7882877134931458217">"Yahoo"</item>
+ <item msgid="5035376313200585242">"Skype"</item>
+ <item msgid="7532363178459444943">"QQ"</item>
+ <item msgid="3713441034299660749">"Google ଟକ୍"</item>
+ <item msgid="2506857312718630823">"ICQ"</item>
+ <item msgid="1648797903785279353">"Jabber"</item>
+ </string-array>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"କଷ୍ଟମ୍"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"ହୋମ୍"</string>
+ <string name="phoneTypeMobile" msgid="6501463557754751037">"ମୋବାଇଲ୍"</string>
+ <string name="phoneTypeWork" msgid="8863939667059911633">"ୱାର୍କ"</string>
+ <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ୱାର୍କ ଫାକ୍ସ"</string>
+ <string name="phoneTypeFaxHome" msgid="2067265972322971467">"ହୋମ୍ ଫାକ୍ସ"</string>
+ <string name="phoneTypePager" msgid="7582359955394921732">"ପେଜର୍"</string>
+ <string name="phoneTypeOther" msgid="1544425847868765990">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="phoneTypeCallback" msgid="2712175203065678206">"କଲବ୍ୟାକ୍"</string>
+ <string name="phoneTypeCar" msgid="8738360689616716982">"କାର୍"</string>
+ <string name="phoneTypeCompanyMain" msgid="540434356461478916">"କମ୍ପାନୀର ମୁଖ୍ୟ"</string>
+ <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
+ <string name="phoneTypeMain" msgid="6766137010628326916">"ମୁଖ୍ୟ"</string>
+ <string name="phoneTypeOtherFax" msgid="8587657145072446565">"ଅନ୍ୟ ଫାକ୍ସ"</string>
+ <string name="phoneTypeRadio" msgid="4093738079908667513">"ରେଡିଓ"</string>
+ <string name="phoneTypeTelex" msgid="3367879952476250512">"ଟେଲେକ୍ସ"</string>
+ <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
+ <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"ୱାର୍କ ମୋବାଇଲ୍"</string>
+ <string name="phoneTypeWorkPager" msgid="649938731231157056">"ୱାର୍କ ପେଜର୍"</string>
+ <string name="phoneTypeAssistant" msgid="5596772636128562884">"ସହାୟକ"</string>
+ <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"କଷ୍ଟମ୍"</string>
+ <string name="eventTypeBirthday" msgid="2813379844211390740">"ଜନ୍ମଦିନ"</string>
+ <string name="eventTypeAnniversary" msgid="3876779744518284000">"ଆନିଭର୍ସରୀ"</string>
+ <string name="eventTypeOther" msgid="7388178939010143077">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"କଷ୍ଟମ୍"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"ହୋମ୍"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"ୱାର୍କ"</string>
+ <string name="emailTypeOther" msgid="2923008695272639549">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="emailTypeMobile" msgid="119919005321166205">"ମୋବାଇଲ୍"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"କଷ୍ଟମ୍"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"ହୋମ୍"</string>
+ <string name="postalTypeWork" msgid="5268172772387694495">"ୱାର୍କ"</string>
+ <string name="postalTypeOther" msgid="2726111966623584341">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"କଷ୍ଟମ୍"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"ହୋମ୍"</string>
+ <string name="imTypeWork" msgid="1371489290242433090">"ୱାର୍କ"</string>
+ <string name="imTypeOther" msgid="5377007495735915478">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"କଷ୍ଟମ୍"</string>
+ <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
+ <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
+ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
+ <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
+ <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"ହ୍ୟାଙ୍ଗଆଉଟ୍ସ"</string>
+ <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
+ <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
+ <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
+ <string name="orgTypeWork" msgid="29268870505363872">"ୱାର୍କ"</string>
+ <string name="orgTypeOther" msgid="3951781131570124082">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"କଷ୍ଟମ୍"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"କଷ୍ଟମ୍"</string>
+ <string name="relationTypeAssistant" msgid="6274334825195379076">"ସହାୟକ"</string>
+ <string name="relationTypeBrother" msgid="8757913506784067713">"ଭାଇ"</string>
+ <string name="relationTypeChild" msgid="1890746277276881626">"ଶିଶୁ"</string>
+ <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"ଡୋମେଷ୍ଟିକ୍ ପାର୍ଟନର୍"</string>
+ <string name="relationTypeFather" msgid="5228034687082050725">"ପିତା"</string>
+ <string name="relationTypeFriend" msgid="7313106762483391262">"ସାଙ୍ଗ"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"ମ୍ୟାନେଜର୍"</string>
+ <string name="relationTypeMother" msgid="4578571352962758304">"ମାତା"</string>
+ <string name="relationTypeParent" msgid="4755635567562925226">"ଅଭିଭାବକ"</string>
+ <string name="relationTypePartner" msgid="7266490285120262781">"ସହଭାଗୀ"</string>
+ <string name="relationTypeReferredBy" msgid="101573059844135524">"ରେଫର୍ କରିଛନ୍ତି"</string>
+ <string name="relationTypeRelative" msgid="1799819930085610271">"ସମ୍ପର୍କୀୟ"</string>
+ <string name="relationTypeSister" msgid="1735983554479076481">"ଭଉଣୀ"</string>
+ <string name="relationTypeSpouse" msgid="394136939428698117">"ସ୍ଵାମୀ ବା ସ୍ତ୍ରୀ"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"କଷ୍ଟମ୍"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"ଘର"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"ୱାର୍କ"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"ଅନ୍ୟାନ୍ୟ"</string>
+ <string name="quick_contacts_not_available" msgid="746098007828579688">"ଏହି ଯୋଗାଯୋଗ ଦେଖିବାକୁ କୌଣସି ଆପ୍ଲିକେଶନ୍ ମିଳିଲା ନାହିଁ।"</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN କୋଡ୍ ଟାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK ଓ ନୂଆ PIN କୋଡ୍ ଟାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK କୋଡ୍"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"ନୂଆ PIN କୋଡ୍"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"ପାସ୍ୱର୍ଡ ଟାଇପ୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ଅନଲକ୍ କରିବାକୁ ପାସୱର୍ଡ ଟାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ଅନଲକ୍ କରିବାକୁ PIN ଟାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ଭୁଲ PIN କୋଡ୍।"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"ଅନଲକ୍ କରିବା ପାଇଁ, ପ୍ରଥମେ ମେନୁ ଓ ତା’ପରେ 0 ଦବାନ୍ତୁ।"</string>
+ <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ଜରୁରୀକାଳୀନ ନମ୍ବର୍"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"କୌଣସି ସେବା ନାହିଁ"</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"ସ୍କ୍ରୀନ୍ ଲକ୍ ହୋଇଯାଇଛି।"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ କିମ୍ବା ଜରୁରୀକାଳୀନ କଲ୍ କରନ୍ତୁ।"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"ଅନଲକ୍ କରିବା ପାଇଁ ପାଟର୍ନ ଆଙ୍କନ୍ତୁ"</string>
+ <string name="lockscreen_emergency_call" msgid="5298642613417801888">"ଜରୁରୀକାଳୀନ"</string>
+ <string name="lockscreen_return_to_call" msgid="5244259785500040021">"କଲ୍କୁ ଫେରନ୍ତୁ"</string>
+ <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"ଠିକ୍!"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="lockscreen_storage_locked" msgid="9167551160010625200">"ସମସ୍ତ ସୁବିଧା ତଥା ଡାଟା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"ମାଲିକର ମୁହଁ ଚିହ୍ନି ଅନଲକ୍ କରିବାର ସର୍ବାଧିକ ଧାର୍ଯ୍ୟ ସୀମା ଅତିକ୍ରମ କଲା"</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"କୌଣସି SIM କାର୍ଡ ନାହିଁ"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ଟାବଲେଟ୍ରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"ଟିଭିରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"ଫୋନ୍ରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"ଏକ SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ।"</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM କାର୍ଡ ନାହିଁ କିମ୍ବା ଖରାପ ଅଛି। SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ।"</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM କାର୍ଡଟି ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ।"</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"ଆପଣଙ୍କ SIM କାର୍ଡକୁ ସ୍ଥାୟୀ ରୂପେ ଅକ୍ଷମ କରିଦିଆଯାଇଛି।\n ଅନ୍ୟ SIM କାର୍ଡ ପାଇଁ ଆପଣଙ୍କ ୱାୟରଲେସ୍ ସେବା ପ୍ରଦାନକାରୀଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"ପୂର୍ବବର୍ତ୍ତୀ ଟ୍ରାକ୍"</string>
+ <string name="lockscreen_transport_next_description" msgid="573285210424377338">"ପରବର୍ତ୍ତୀ ଟ୍ରାକ୍"</string>
+ <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"ପଜ୍ କରନ୍ତୁ"</string>
+ <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"ପ୍ଲେ କରନ୍ତୁ"</string>
+ <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"ପଛକୁ ନିଅନ୍ତୁ"</string>
+ <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"ଫାଷ୍ଟ ଫର୍ୱାର୍ଡ"</string>
+ <string name="emergency_calls_only" msgid="6733978304386365407">"କେବଳ ଜରୁରୀକାଳୀନ କଲ୍"</string>
+ <string name="lockscreen_network_locked_message" msgid="143389224986028501">"ନେଟ୍ୱର୍କକୁ ଲକ୍ କରାଯାଇଛି"</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM କାର୍ଡଟିରେ PUK ଲକ୍ ହୋଇଯାଇଛି।"</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"ୟୁଜର୍ ଗାଇଡ୍ ଦେଖନ୍ତୁ କିମ୍ବା ଗ୍ରାହକ ସେବା କେନ୍ଦ୍ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM କାର୍ଡ ଲକ୍ ହୋଇଯାଇଛି"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM କାର୍ଡକୁ ଅନଲକ୍ କରାଯାଉଛି…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"ଆପଣଙ୍କ ପାସୱର୍ଡକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"ଆପଣଙ୍କ PINକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ, Google ସାଇନ୍-ଇନ୍ ବ୍ୟବହାର କରି ଆପଣଙ୍କୁ ନିଜ ଟାବଲେଟ୍କୁ ଅନଲକ୍ କରିବାକୁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"ଆପଣ ନିଜର ଲକ୍ ଖୋଲିବା ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଆଙ୍କିଛନ୍ତି। ଅଧିକ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଅସଫଳ ଚେଷ୍ଟା ପରେ ଆପଣଙ୍କ Google ସାଇନ୍-ଇନ୍ର ବ୍ୟବହାର କରି ନିଜ TV କୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ। \n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ, Google ସାଇନ୍-ଇନ୍ ବ୍ୟବହାର କରି ଆପଣଙ୍କୁ ନିଜ ଫୋନ୍କୁ ଅନଲକ୍ କରିବାକୁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"ଟାବଲେଟ୍କୁ ଅନ୍ଲକ୍ କରିବା ପାଇଁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ, ଟାବଲେଟ୍ଟି ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ ଏବଂ ଆପଣ ସମସ୍ତ ୟୁଜର୍ ଡାଟା ହରାଇବେ।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"ଟିଭିକୁ ଅନଲକ୍ କରିବା ପାଇଁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ୍ ପ୍ରୟାସ କଲେ। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଟିଭିଟି ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ ଏବଂ ସମସ୍ତ ୟୁଜର୍ ଡାଟା ବାହାରିଯିବ।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"ଫୋନ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ, ଫୋନ୍ଟି ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ ଏବଂ ଆପଣ ସମସ୍ତ ୟୁଜର୍ ଡାଟା ହରାଇବେ।"</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"ଟାବଲେଟ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଟାବଲେଟ୍ଟି ବର୍ତ୍ତମାନ ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ।"</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"ଟିଭିକୁ ଅନଲକ୍ କରିବା ପାଇଁ ଆପଣ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ୍ ପ୍ରୟାସ କଲେ। ଟିଭିଟି ବର୍ତ୍ତମାନ ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ।"</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"ଫୋନ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଫୋନ୍ଟି ବର୍ତ୍ତମାନ ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ।"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"ପାଟର୍ନ ଭୁଲି ଯାଇଛନ୍ତି କି?"</string>
+ <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"ଆକାଉଣ୍ଟ ଅନଲକ୍"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"ଅତ୍ୟଧିକ ପାଟର୍ନ ଉଦ୍ୟମ"</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"ଅନଲକ୍ କରିବା ପାଇଁ, ନିଜ Google ଆକାଉଣ୍ଟରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ।"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ୟୁଜରନେମ୍ (ଇମେଲ୍)"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ପାସ୍ୱର୍ଡ:"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ସାଇନ୍-ଇନ୍"</string>
+ <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ୟୁଜର୍ନେମ୍ କିମ୍ୱା ପାସ୍ୱର୍ଡ ଭୁଲ୍ ଅଛି।"</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"ଆପଣଙ୍କର ଯୁଜରନେମ୍ କିମ୍ୱା ପାସୱାର୍ଡ ଭୁଲି ଯାଇଛନ୍ତି କି?\n"<b>"google.com/accounts/recovery"</b>" ଭିଜିଟ୍ କରନ୍ତୁ।"</string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
+ <string name="lockscreen_unlock_label" msgid="737440483220667054">"ଅନଲକ୍"</string>
+ <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ସାଉଣ୍ଡ ଅନ୍ ଅଛି"</string>
+ <string name="lockscreen_sound_off_label" msgid="996822825154319026">"ସାଉଣ୍ଡ ଅଫ୍ ଅଛି"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"ପାଟର୍ନ ଆରମ୍ଭ ହେଲା"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"ପାଟର୍ନ ଖାଲି କରାଗଲା"</string>
+ <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"ସେଲ୍ ଯୋଡ଼ାଗଲା"</string>
+ <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"ସେଲ୍ <xliff:g id="CELL_INDEX">%1$s</xliff:g> ଯୋଡ଼ାଗଲା"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"ପାଟର୍ନ ସମ୍ପୂର୍ଣ୍ଣ ହେଲା"</string>
+ <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"ପାଟର୍ନ କ୍ଷେତ୍ର।"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s। %3$dରୁ %2$d ୱିଜେଟ୍।"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ୱିଜେଟ୍ ଯୋଡ଼ନ୍ତୁ।"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ଖାଲି କରନ୍ତୁ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ଅନଲକ୍ କ୍ଷେତ୍ରକୁ ବଢ଼ାଇଦିଆଯାଇଛି।"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ଅନଲକ୍ କ୍ଷେତ୍ର ଛୋଟ କରିଦିଆଯାଇଛି।"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ୱିଜେଟ୍।"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ୟୁଜର୍ ଚୟନକାରୀ"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ସ୍ଥିତି"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"କ୍ୟାମେରା"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ମିଡିଆ ନିୟନ୍ତ୍ରଣ"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ୱିଜେଟ୍ ପୁନଃ ସଜାଇବା ଆରମ୍ଭ ହେଲା।"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ୱିଜେଟ୍ ପୁନଃ ସଜାଇବା ଶେଷ ହେଲା।"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ୱିଜେଟ୍ ଡିଲିଟ୍ କରିଦିଆଗଲା।"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ଅନଲକ୍ କ୍ଷେତ୍ରକୁ ବଢ଼ାନ୍ତୁ।"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ସ୍ଲାଇଡ୍ ଅନଲକ୍।"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ପାଟର୍ନ ଅନଲକ୍।"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ଫେସ୍ ଅନଲକ୍।"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN ଅନଲକ୍।"</string>
+ <!-- no translation found for keyguard_accessibility_sim_pin_unlock (9149698847116962307) -->
+ <skip />
+ <!-- no translation found for keyguard_accessibility_sim_puk_unlock (9106899279724723341) -->
+ <skip />
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ପାସ୍ୱର୍ଡ ଅନଲକ୍।"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ପାଟର୍ନ କ୍ଷେତ୍ର।"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"ସ୍ଲାଇଡ୍ କ୍ଷେତ୍ର।"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="granularity_label_character" msgid="7336470535385009523">"ବର୍ଣ୍ଣ"</string>
+ <string name="granularity_label_word" msgid="7075570328374918660">"ଶବ୍ଦ"</string>
+ <string name="granularity_label_link" msgid="5815508880782488267">"ଲିଙ୍କ"</string>
+ <string name="granularity_label_line" msgid="5764267235026120888">"ରେଖା"</string>
+ <string name="factorytest_failed" msgid="5410270329114212041">"ଫ୍ୟାକ୍ଟୋରୀ ଟେଷ୍ଟ ବିଫଳ ହୋଇଛି"</string>
+ <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST କାର୍ଯ୍ୟ କରିବା ପାଇଁ /system/appରେ ଇନଷ୍ଟଲ୍ ହୋଇଥିବା ପ୍ୟାକେଜ୍ ପାଇଁ କେବଳ ସପୋର୍ଟ କରେ।"</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST କାର୍ଯ୍ୟ କରିବା ପାଇଁ କୌଣସି ପ୍ୟାକେଜ୍ ମିଲିଲା ନାହିଁ।"</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"ରିବୁଟ୍ କରନ୍ତୁ"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"\"<xliff:g id="TITLE">%s</xliff:g>\" ରେ ଥିବା ପୃଷ୍ଠାଟି କୁହେ:"</string>
+ <string name="js_dialog_title_default" msgid="6961903213729667573">"ଜାଭାସ୍କ୍ରୀପ୍ଟ"</string>
+ <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"ନେଭିଗେଶନ୍ ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"ଏହି ପୃଷ୍ଠାରୁ ବାହାରିଯାଆନ୍ତୁ"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"ଏହି ପୃଷ୍ଠାରେ ରୁହନ୍ତୁ"</string>
+ <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nଆପଣ କ’ଣ ପ୍ରକୃତରେ ଏହି ପୃଷ୍ଠାରୁ ଦୂରକୁ ନେଭିଗେଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି?"</string>
+ <string name="save_password_label" msgid="6860261758665825069">"ନିଶ୍ଚିତ କରନ୍ତୁ"</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"ଧ୍ୟାନଦିଅନ୍ତୁ: ଜୁମ୍ ଇନ୍ ଓ ଆଉଟ୍ କରିବା ପାଇଁ ଡବଲ୍-ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="autofill_this_form" msgid="4616758841157816676">"ସ୍ୱତଃପୂରଣ"</string>
+ <string name="setup_autofill" msgid="7103495070180590814">"ଅଟୋଫିଲ୍ ସେଟ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for autofill_window_title (921006636895825007) -->
+ <skip />
+ <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
+ <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
+ <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"ଅଞ୍ଚଳ"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"ପୋଷ୍ଟାଲ୍ କୋଡ୍"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"ରାଜ୍ୟ"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"ZIP କୋଡ୍"</string>
+ <string name="autofill_county" msgid="237073771020362891">"କାଉଣ୍ଟୀ"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"ଆଇଲ୍ୟାଣ୍ଡ"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"ଜିଲ୍ଲା"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"ବିଭାଗ"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"ପ୍ରଶାସକୀୟ କ୍ଷେତ୍ର"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"ପ୍ୟାରିସ୍"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"କ୍ଷେତ୍ର"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"ଭୂଖଣ୍ଡ"</string>
+ <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"ଆପଣଙ୍କ ୱେବ୍ ବୁକ୍ମାର୍କ ଓ ହିଷ୍ଟୋରୀ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"ବ୍ରାଉଜର୍ରେ ଭିଜିଟ୍ କରାଯାଇଥିବା ସମସ୍ତ URL ପଢ଼ିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଧ୍ୟାନଦିଅନ୍ତୁ: ଏହି ଅନୁମତି ୱେବ୍ ବ୍ରାଉଜ୍ କରିବା ଦକ୍ଷତା ତୃତୀୟ-ପକ୍ଷ ବ୍ରାଉଜର୍ କିମ୍ବା ଅନ୍ୟାନ୍ୟ ଆପ୍ଲିକେଶନ୍ରେ ଲାଗୁ କରାଯାଇନପାରେ।"</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"ୱେବ୍ ବୁକ୍ମାର୍କ ଓ ହିଷ୍ଟୋରୀ ଲେଖନ୍ତୁ"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"ଆପଣଙ୍କ ଟାବ୍ଲେଟ୍ରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ବ୍ରାଉଜର୍ ହିଷ୍ଟୋରୀ କିମ୍ବା ବୁକ୍ମାର୍କଗୁଡ଼ିକ ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହାଦ୍ୱାରା ଆପ୍ଟି ବ୍ରାଉଜର୍ ଡାଟା ଲିଭାଇପାରେ କିମ୍ବା ବଦଳାଇପାରେ। ଧ୍ୟାନଦିଅନ୍ତୁ: ଏହି ଅନୁମତି ୱେବ୍ ବ୍ରାଉଜ୍ କରିବାର ଦକ୍ଷତା ତୃତୀୟ-ପକ୍ଷ ବ୍ରାଉଜର୍ କିମ୍ବା ଅନ୍ୟାନ୍ୟ ଆପ୍ଲିକେଶନ୍ରେ ଲାଗୁ କରାଯାଇନପାରେ।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"ଆପଣଙ୍କ ଟିଭିରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ବ୍ରାଉଜର୍ ହିଷ୍ଟୋରୀ କିମ୍ବା ବୁକମାର୍କଗୁଡ଼ିକ ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହାଦ୍ୱାରା ଆପ୍ଟି ବ୍ରାଉଜର୍ ଡାଟା ଲିଭାଇପାରେ କିମ୍ବା ବଦଳାଇପାରେ। ଧ୍ୟାଦିଅନ୍ତୁ: ଏହି ଅନୁମତି ୱେବ୍ ବ୍ରାଉଜ୍ କରିବା ଦକ୍ଷତା ତୃତୀୟ-ପକ୍ଷ ବ୍ରାଉଜର୍ କିମ୍ବା ଅନ୍ୟାନ୍ୟ ଆପ୍ଲିକେ୍ନ୍ଶରେ ଲାଗୁ କରାଯାଇନପାରେ।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ଆପଣଙ୍କ ଫୋନ୍ରେ ଷ୍ଟୋର୍ କରାଯାଇଥିବା ବ୍ରାଉଜର୍ ହିଷ୍ଟୋରୀ କିମ୍ବା ବୁକ୍ମାର୍କଗୁଡ଼ିକ ବଦଳାଇବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଏହାଦ୍ୱାରା ଆପ୍ଟି ବ୍ରାଉଜର୍ ଡାଟା ଲିଭାଇପାରେ କିମ୍ବା ବଦଳାଇପାରେ। ଧ୍ୟାନଦିଅନ୍ତୁ: ଏହି ଅନୁମତି ୱେବ୍ ବ୍ରାଉଜ୍ କରିବାର ଦକ୍ଷତା ତୃତୀୟ-ପକ୍ଷ ବ୍ରାଉଜର୍ କିମ୍ବା ଅନ୍ୟାନ୍ୟ ଆପ୍ଲିକେଶନ୍ରେ ଲାଗୁ କରାଯାଇନପାରେ।"</string>
+ <string name="permlab_setAlarm" msgid="1379294556362091814">"ଏକ ଆଲର୍ମ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"ଆପ୍କୁ, ଇନଷ୍ଟଲ୍ ହୋଇଥିବା ଆଲାର୍ମ କ୍ଲକ୍ ଆପ୍ରେ ଏକ ଆଲାର୍ମ ସେଟ୍ କରିବାକୁ ଦେଇଥାଏ। କିଛି ଆଲର୍ମ କ୍ଲକ୍ ଆପ୍ ଏହି ବୈଶିଷ୍ଟ୍ୟ ଲାଗୁ କରିନପାରନ୍ତି।"</string>
+ <string name="permlab_addVoicemail" msgid="5525660026090959044">"ଭଏସ୍ମେଲ୍ ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"ଆପଣଙ୍କ ଭଏସମେଲ୍ ଇନ୍ବକ୍ସରେ ମେସେଜ୍ ଯୋଡ଼ିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ବ୍ରାଉଜରର ଭୌଗଳିକ ଅନୁମତି ସଂଶୋଧନ କରନ୍ତୁ"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ଆପ୍କୁ, ବ୍ରାଉଜର୍ର ଭୌଗଳିକ ଅନୁମତି ବଦଳାଇବାକୁ ଦେଇଥାଏ। ହାନୀକାରକ ଆପ୍ ଆର୍ବିଟେରୀ ୱେବ୍ ସାଇଟଗୁଡ଼ିକୁ ଲୋକେଶନ୍ ସୂଚନା ପଠାଇବା ପାଇଁ ଏହା ବ୍ୟବହାର କରିପାରନ୍ତି।"</string>
+ <string name="save_password_message" msgid="767344687139195790">"ବ୍ରାଉଜର୍ ଏହି ପାସୱର୍ଡକୁ ମନେରଖୁ ବୋଲି ଆପଣ ଚାହୁଁଛନ୍ତି କି?"</string>
+ <string name="save_password_notnow" msgid="6389675316706699758">"ବର୍ତ୍ତମାନ ନୁହେଁଁ"</string>
+ <string name="save_password_remember" msgid="6491879678996749466">"ମନେରଖନ୍ତୁ"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"କଦାପି ନୁହେଁ"</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"ଏହି ପୃଷ୍ଠା ଖୋଲିବାକୁ ଆପଣଙ୍କ ପାଖରେ ଅନୁମତି ନାହିଁ।"</string>
+ <string name="text_copied" msgid="4985729524670131385">"ଟେକ୍ସଟ୍ କ୍ଲିପବୋର୍ଡକୁ କପୀ ହୋଇଯାଇଛି"</string>
+ <string name="more_item_label" msgid="4650918923083320495">"ଅଧିକ"</string>
+ <string name="prepend_shortcut_label" msgid="2572214461676015642">"ମେନୁ"</string>
+ <string name="menu_space_shortcut_label" msgid="2410328639272162537">"ସ୍ପେସ୍"</string>
+ <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"ଏଣ୍ଟର୍"</string>
+ <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ଡିଲିଟ୍"</string>
+ <string name="search_go" msgid="8298016669822141719">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="search_hint" msgid="1733947260773056054">"ସର୍ଚ୍ଚ…"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="searchview_description_query" msgid="5911778593125355124">"କ୍ୱେରୀ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"କ୍ୱେରୀ ଖାଲି କରନ୍ତୁ"</string>
+ <string name="searchview_description_submit" msgid="2688450133297983542">"କ୍ୱେରୀ ଦାଖଲ କରନ୍ତୁ"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"ଭଏସ୍ ସର୍ଚ୍ଚ"</string>
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"’ସ୍ପର୍ଶ କରି ଏକ୍ସପ୍ଲୋର୍ କରନ୍ତୁ’ ସକ୍ଷମ କରିବେ?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ’ସ୍ପର୍ଶ କରି ଏକ୍ସପ୍ଲୋର୍ କରନ୍ତୁ’ ସକ୍ଷମ କରିବାକୁ ଚାହେଁ। ’ସ୍ପର୍ଶ କରି ଏକ୍ସପ୍ଲୋର୍ କରନ୍ତୁ’ ଅନ୍ ଥିବାବେଳେ, ଆପଣଙ୍କ ଆଙ୍ଗୁଠି ତଳେ କ’ଣ ଅଛି, ତାହାର ବ୍ୟାଖ୍ୟା ଦେଖିପାରିବେ କିମ୍ବା ଟାବ୍ଲେଟ୍ ସହ କଥାବାର୍ତ୍ତା କରିବାକୁ ଜେଶ୍ଚର୍ କରିପାରିବେ।"</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ’ସ୍ପର୍ଶ କରି ଏକ୍ସପ୍ଲୋର୍ କରନ୍ତୁ’ ସକ୍ଷମ କରିବାକୁ ଚାହେଁ। ’ସ୍ପର୍ଶ କରି ଏକ୍ସପ୍ଲୋର୍ କରନ୍ତୁ’ ଅନ୍ ଥିବାବେଳେ, ଆପଣଙ୍କ ଆଙ୍ଗୁଠି ତଳେ କ’ଣ ଅଛି, ତାହାର ବ୍ୟାଖ୍ୟା ଦେଖିପାରିବେ କିମ୍ବା ଫୋନ୍ ସହ କଥାବାର୍ତ୍ତା କରିବାକୁ ଜେଶ୍ଚର୍ କରିପାରିବେ।"</string>
+ <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ମାସ ପୂର୍ବରୁ"</string>
+ <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ମାସ ପୂର୍ବରୁ"</string>
+ <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+ <item quantity="other">ଶେଷ <xliff:g id="COUNT_1">%d</xliff:g> ଦିନ</item>
+ <item quantity="one">ଶେଷ <xliff:g id="COUNT_0">%d</xliff:g> ଦିନ</item>
+ </plurals>
+ <string name="last_month" msgid="3959346739979055432">"ଶେଷ ମାସ"</string>
+ <string name="older" msgid="5211975022815554840">"ପୁରାତନ"</string>
+ <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>ରେ"</string>
+ <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>ରେ"</string>
+ <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>ରେ"</string>
+ <string name="day" msgid="8144195776058119424">"ଦିନ"</string>
+ <string name="days" msgid="4774547661021344602">"ଦିନ"</string>
+ <string name="hour" msgid="2126771916426189481">"ଘଣ୍ଟା"</string>
+ <string name="hours" msgid="894424005266852993">"ଘଣ୍ଟା"</string>
+ <string name="minute" msgid="9148878657703769868">"ମିନିଟ୍"</string>
+ <string name="minutes" msgid="5646001005827034509">"ମିନିଟ୍"</string>
+ <string name="second" msgid="3184235808021478">"ସେକେଣ୍ଡ"</string>
+ <string name="seconds" msgid="3161515347216589235">"ସେକେଣ୍ଡ"</string>
+ <string name="week" msgid="5617961537173061583">"ସପ୍ତାହ"</string>
+ <string name="weeks" msgid="6509623834583944518">"ସପ୍ତାହ"</string>
+ <string name="year" msgid="4001118221013892076">"ବର୍ଷ"</string>
+ <string name="years" msgid="6881577717993213522">"ବର୍ଷ"</string>
+ <string name="now_string_shortest" msgid="8912796667087856402">"ବର୍ତ୍ତମାନ"</string>
+ <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ମିନିଟ୍</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ମିନିଟ୍</item>
+ </plurals>
+ <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ଘଣ୍ଟା</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ଘଣ୍ଟା</item>
+ </plurals>
+ <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ଦିନ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ଦିନ</item>
+ </plurals>
+ <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ବର୍ଷ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ବର୍ଷ</item>
+ </plurals>
+ <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ମିନିଟରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ମିନିଟରେ</item>
+ </plurals>
+ <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ଘଣ୍ଟାରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ଘଣ୍ଟାରେ</item>
+ </plurals>
+ <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ଦିନରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ଦିନରେ</item>
+ </plurals>
+ <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ବର୍ଷରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ବର୍ଷରେ</item>
+ </plurals>
+ <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ମିନିଟ୍ ପୂର୍ବେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ମିନିଟ୍ ପୂର୍ବେ</item>
+ </plurals>
+ <plurals name="duration_hours_relative" formatted="false" msgid="676894109982008411">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ଘଣ୍ଟା ପୂର୍ବେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ଘଣ୍ଟା ପୂର୍ବେ</item>
+ </plurals>
+ <plurals name="duration_days_relative" formatted="false" msgid="2203515825765397130">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ଦିନ ପୂର୍ବେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ଦିନ ପୂର୍ବେ</item>
+ </plurals>
+ <plurals name="duration_years_relative" formatted="false" msgid="4820062134188885734">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ବର୍ଷ ପୂର୍ବେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ବର୍ଷ ପୂର୍ବେ</item>
+ </plurals>
+ <plurals name="duration_minutes_relative_future" formatted="false" msgid="4655043589817680966">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ମିନିଟରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ମିନିଟରେ</item>
+ </plurals>
+ <plurals name="duration_hours_relative_future" formatted="false" msgid="8084579714205223891">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ଘଣ୍ଟାରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ଘଣ୍ଟାରେ</item>
+ </plurals>
+ <plurals name="duration_days_relative_future" formatted="false" msgid="333215369363433992">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ଦିନରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ଦିନରେ</item>
+ </plurals>
+ <plurals name="duration_years_relative_future" formatted="false" msgid="8644862986413104011">
+ <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ବର୍ଷରେ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ବର୍ଷରେ</item>
+ </plurals>
+ <string name="VideoView_error_title" msgid="3534509135438353077">"ଭିଡିଓ ସମସ୍ୟା"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ଏହି ଡିଭାଇସ୍କୁ ଷ୍ଟ୍ରିମ୍ କରିବା ପାଇଁ ଏହି ଭିଡିଓ ମାନ୍ୟ ନୁହେଁ।"</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ଏହି ଭିଡିଓ ଚଲାଇ ହେବନାହିଁ"</string>
+ <string name="VideoView_error_button" msgid="2822238215100679592">"ଠିକ୍ ଅଛି"</string>
+ <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon" msgid="7245353528818587908">"ମଧ୍ୟାହ୍ନ"</string>
+ <string name="Noon" msgid="3342127745230013127">"ମଧ୍ୟାହ୍ନ"</string>
+ <string name="midnight" msgid="7166259508850457595">"ମଧ୍ୟରାତ୍ର"</string>
+ <string name="Midnight" msgid="5630806906897892201">"ମଧ୍ୟରାତ୍ର"</string>
+ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll" msgid="6876518925844129331">"ସବୁ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="cut" msgid="3092569408438626261">"କଟ୍"</string>
+ <string name="copy" msgid="2681946229533511987">"କପୀ"</string>
+ <!-- no translation found for failed_to_copy_to_clipboard (1833662432489814471) -->
+ <skip />
+ <string name="paste" msgid="5629880836805036433">"ପେଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"ସାଦା ଟେକ୍ସଟ୍ ଭାବରେ ପେଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="replace" msgid="5781686059063148930">"ବଦଳାନ୍ତୁ…"</string>
+ <string name="delete" msgid="6098684844021697789">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"URL କପୀ କରନ୍ତୁ"</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"ଟେକ୍ସଟ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="undo" msgid="7905788502491742328">"ପୂର୍ବ ପରି କରନ୍ତୁ"</string>
+ <string name="redo" msgid="7759464876566803888">"ପୁଣି କରନ୍ତୁ"</string>
+ <!-- no translation found for autofill (3035779615680565188) -->
+ <skip />
+ <string name="textSelectionCABTitle" msgid="5236850394370820357">"ଟେକ୍ସଟ୍ ଚୟନ"</string>
+ <string name="addToDictionary" msgid="4352161534510057874">"ଶବ୍ଦକୋଷରେ ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="deleteText" msgid="6979668428458199034">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="inputMethod" msgid="1653630062304567879">"ଇନପୁଟ୍ ପଦ୍ଧତି"</string>
+ <string name="editTextMenuTitle" msgid="4909135564941815494">"ଟେକ୍ସଟ୍ କାର୍ଯ୍ୟ"</string>
+ <!-- no translation found for email (4560673117055050403) -->
+ <skip />
+ <!-- no translation found for dial (1253998302767701559) -->
+ <skip />
+ <!-- no translation found for map (6521159124535543457) -->
+ <skip />
+ <!-- no translation found for browse (1245903488306147205) -->
+ <skip />
+ <!-- no translation found for sms (4560537514610063430) -->
+ <skip />
+ <!-- no translation found for add_contact (7867066569670597203) -->
+ <skip />
+ <!-- no translation found for view_calendar (979609872939597838) -->
+ <skip />
+ <!-- no translation found for add_calendar_event (1953664627192056206) -->
+ <skip />
+ <!-- no translation found for view_flight (7691640491425680214) -->
+ <skip />
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"ଷ୍ଟୋରେଜ୍ ସ୍ପେସ୍ ଶେଷ ହେବାରେ ଲାଗିଛି"</string>
+ <string name="low_internal_storage_view_text" msgid="6640505817617414371">"କିଛି ସିଷ୍ଟମ ଫଙ୍କଶନ୍ କାମ କରିନପାରେ"</string>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ସିଷ୍ଟମ୍ ପାଇଁ ପ୍ରର୍ଯ୍ୟାପ୍ତ ଷ୍ଟୋରେଜ୍ ନାହିଁ। ସୁନିଶ୍ଚିତ କରନ୍ତୁ ଯେ, ଆପଣଙ୍କ ପାଖରେ 250MB ଖାଲି ଜାଗା ଅଛି ଏବଂ ପୁନଃ ଆରମ୍ଭ କରନ୍ତୁ।"</string>
+ <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string>
+ <string name="app_running_notification_text" msgid="1197581823314971177">"ଅଧିକ ସୂଚନା ପାଇଁ କିମ୍ବା ଆପ୍ ବନ୍ଦ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="ok" msgid="5970060430562524910">"ଠିକ୍ ଅଛି"</string>
+ <string name="cancel" msgid="6442560571259935130">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="yes" msgid="5362982303337969312">"ଠିକ୍ ଅଛି"</string>
+ <string name="no" msgid="5141531044935541497">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="dialog_alert_title" msgid="2049658708609043103">"ଧ୍ୟାନଦିଅନ୍ତୁ"</string>
+ <string name="loading" msgid="7933681260296021180">"ଲୋଡ୍ କରାଯାଉଛି…"</string>
+ <string name="capital_on" msgid="1544682755514494298">"ଅନ୍"</string>
+ <string name="capital_off" msgid="6815870386972805832">"ଅଫ୍"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
+ <string name="whichApplicationNamed" msgid="8260158865936942783">"%1$s ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
+ <!-- no translation found for whichApplicationLabel (7425855495383818784) -->
+ <skip />
+ <string name="whichViewApplication" msgid="3272778576700572102">"ସହିତ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ସହିତ ଖୋଲନ୍ତୁ"</string>
+ <!-- no translation found for whichViewApplicationLabel (2666774233008808473) -->
+ <skip />
+ <string name="whichEditApplication" msgid="144727838241402655">"ସହିତ ଏଡିଟ୍ କରନ୍ତୁ"</string>
+ <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sରେ ସଂଶୋଧନ କରନ୍ତୁ"</string>
+ <!-- no translation found for whichEditApplicationLabel (7183524181625290300) -->
+ <skip />
+ <string name="whichSendApplication" msgid="6902512414057341668">"ଏହାଙ୍କ ସହ ଶେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="whichSendApplicationNamed" msgid="2799370240005424391">"%1$s ସହିତ ଶେୟାର୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for whichSendApplicationLabel (4579076294675975354) -->
+ <skip />
+ <!-- no translation found for whichSendToApplication (8272422260066642057) -->
+ <skip />
+ <!-- no translation found for whichSendToApplicationNamed (7768387871529295325) -->
+ <skip />
+ <!-- no translation found for whichSendToApplicationLabel (8878962419005813500) -->
+ <skip />
+ <string name="whichHomeApplication" msgid="4307587691506919691">"ହୋମ୍ ଆପ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"ହୋମ୍ ରୂପରେ %1$s ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <!-- no translation found for whichHomeApplicationLabel (809529747002918649) -->
+ <skip />
+ <!-- no translation found for whichImageCaptureApplication (3680261417470652882) -->
+ <skip />
+ <!-- no translation found for whichImageCaptureApplicationNamed (8619384150737825003) -->
+ <skip />
+ <!-- no translation found for whichImageCaptureApplicationLabel (6390303445371527066) -->
+ <skip />
+ <string name="alwaysUse" msgid="4583018368000610438">"ଏହି କାର୍ଯ୍ୟ ପାଇଁ ଡିଫଲ୍ଟ ଭାବେ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+ <string name="use_a_different_app" msgid="8134926230585710243">"ଏକ ଭିନ୍ନ ଆପ୍ର ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"\"ସିଷ୍ଟମ୍ ସେଟିଙ୍ଗ > ଆପ୍ > ଡାଉନଲୋଡ୍ କରାଯାଇଛି\"ରେ ଡିଫଲ୍ଟ ଖାଲି କରନ୍ତୁ।"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"ଏକ କାର୍ଯ୍ୟାନୁଷ୍ଠାନ ବାଛନ୍ତୁ"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"USB ଡିଭାଇସ୍ ପାଇଁ ଗୋଟିଏ ଆପ୍ ବାଛନ୍ତୁ"</string>
+ <string name="noApplications" msgid="2991814273936504689">"କୌଣସି ଆପ୍ ଏହି କାର୍ଯ୍ୟ କରିପାରିବ ନାହିଁ।"</string>
+ <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <!-- no translation found for aerr_application_repeated (3146328699537439573) -->
+ <skip />
+ <!-- no translation found for aerr_process_repeated (6235302956890402259) -->
+ <skip />
+ <string name="aerr_restart" msgid="7581308074153624475">"ଆପ୍କୁ ପୁଣି ଖୋଲନ୍ତୁ"</string>
+ <string name="aerr_report" msgid="5371800241488400617">"ମତାମତ ପଠାନ୍ତୁ"</string>
+ <string name="aerr_close" msgid="2991640326563991340">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <!-- no translation found for aerr_mute (1974781923723235953) -->
+ <skip />
+ <!-- no translation found for aerr_wait (3199956902437040261) -->
+ <skip />
+ <!-- no translation found for aerr_close_app (3269334853724920302) -->
+ <skip />
+ <string name="anr_title" msgid="4351948481459135709"></string>
+ <!-- no translation found for anr_activity_application (8493290105678066167) -->
+ <skip />
+ <!-- no translation found for anr_activity_process (1622382268908620314) -->
+ <skip />
+ <!-- no translation found for anr_application_process (6417199034861140083) -->
+ <skip />
+ <!-- no translation found for anr_process (6156880875555921105) -->
+ <skip />
+ <string name="force_close" msgid="8346072094521265605">"ଠିକ୍ ଅଛି"</string>
+ <string name="report" msgid="4060218260984795706">"ରିପୋର୍ଟ"</string>
+ <string name="wait" msgid="7147118217226317732">"ଅପେକ୍ଷା କରନ୍ତୁ"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"ଏହି ପୃଷ୍ଠାଟି ଚାଲୁନାହିଁ।\n\nଆପଣ ଏହାକୁ ବନ୍ଦ କରିବେ କି?"</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"ଆପ୍କୁ ରିଡାଇରେକ୍ଟ କରାଗଲା"</string>
+ <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଏବେ ଚାଲୁଅଛି।"</string>
+ <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ବାସ୍ତବିକ ରୂପରେ ଲଞ୍ଚ କରାଯାଇଥିଲା।"</string>
+ <string name="screen_compat_mode_scale" msgid="3202955667675944499">"ସ୍କେଲ୍"</string>
+ <string name="screen_compat_mode_show" msgid="4013878876486655892">"ସର୍ବଦା ଦେଖାନ୍ତୁ"</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"\"ସିଷ୍ଟମ୍ ସେଟିଙ୍ଗ > ଆପ୍ > ଡାଉନଲୋଡ୍ କରାଯାଇଛି\"ରେ ଏହାକୁ ପୁନଃ-ସକ୍ଷମ କରନ୍ତୁ।"</string>
+ <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନର ଡିସ୍ପ୍ଲେ ଆକାର ସେଟିଙ୍ଗ ସପୋର୍ଟ କରେନାହିଁ ଏବଂ ଅପ୍ରତ୍ୟାଶିତ କାର୍ଯ୍ୟ କରିପାରେ।"</string>
+ <string name="unsupported_display_size_show" msgid="7969129195360353041">"ସର୍ବଦା ଦେଖାନ୍ତୁ"</string>
+ <!-- no translation found for unsupported_compile_sdk_message (4253168368781441759) -->
+ <skip />
+ <!-- no translation found for unsupported_compile_sdk_show (2681877855260970231) -->
+ <skip />
+ <!-- no translation found for unsupported_compile_sdk_check_update (3312723623323216101) -->
+ <skip />
+ <string name="smv_application" msgid="3307209192155442829">"ଆପ୍ <xliff:g id="APPLICATION">%1$s</xliff:g> (ପ୍ରକ୍ରିୟା <xliff:g id="PROCESS">%2$s</xliff:g>) ଏହାର ସ୍ୱ-ଲାଗୁ କରାଯାଇଥିବା ଷ୍ଟ୍ରିକ୍ଟ-ମୋଡ୍ ପଲିସୀ ଉଲ୍ଲଂଘନ କରିଛି।"</string>
+ <string name="smv_process" msgid="5120397012047462446">"ଏହି {0/PROCESS<xliff:g id="PROCESS">%1$s</xliff:g> ନିଜ ଦ୍ୱାରା ଲାଗୁ କରାଯାଇଥିବା ଷ୍ଟ୍ରିକ୍ଟମୋଡ୍ ପଲିସୀକୁ ଉଲ୍ଲଂଘନ କରିଛି।"</string>
+ <!-- no translation found for android_upgrading_title (7513829952443484438) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (4503169817302593560) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (7009520271220804517) -->
+ <skip />
+ <!-- no translation found for android_start_title (4536778526365907780) -->
+ <skip />
+ <!-- no translation found for android_start_title (4929837533850340472) -->
+ <skip />
+ <!-- no translation found for android_start_title (7467484093260449437) -->
+ <skip />
+ <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ଷ୍ଟୋରେଜ୍ ବଢ଼ାଯାଉଛି"</string>
+ <!-- no translation found for android_upgrading_notification_title (1511552415039349062) -->
+ <skip />
+ <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅପଗ୍ରେଡ୍ କରାଯାଉଛି…"</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>ରୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଆପ୍ ଅନୁକୂଳନ କରୁଛି।"</string>
+ <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> ପ୍ରସ୍ତୁତ କରାଯାଉଛି।"</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ଆପ୍ ଆରମ୍ଭ କରାଯାଉଛି।"</string>
+ <string name="android_upgrading_complete" msgid="1405954754112999229">"ବୁଟ୍ ସମାପ୍ତ କରୁଛି।"</string>
+ <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ଚାଲୁଛି"</string>
+ <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
+ <skip />
+ <!-- no translation found for old_app_action (3044685170829526403) -->
+ <skip />
+ <!-- no translation found for new_app_action (6694851182870774403) -->
+ <skip />
+ <!-- no translation found for new_app_description (5894852887817332322) -->
+ <skip />
+ <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ଧାର୍ଯ୍ୟ ମେମୋରୀରୁ ବାହାରକୁ ଗଲା"</string>
+ <string name="dump_heap_notification_detail" msgid="6901391084243999274">"ହିପ୍ ଡମ୍ପ ସଂଗ୍ରହ କରାଯାଇଛି; ଶେୟାର୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="dump_heap_title" msgid="5864292264307651673">"ହିପ୍ ଡମ୍ପ ଶେୟାର୍ କରିବେ?"</string>
+ <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> ପ୍ରୋସେସ୍ ଏହାର ଧାର୍ଯ୍ୟ <xliff:g id="SIZE">%2$s</xliff:g> ମେମୋରୀ ସୀମାରୁ ବାହରକୁ ଗଲା। ଏହାର ଡେଭଲପରଙ୍କ ସହ ଶେୟାର୍ କରିବାକୁ ଏକ ହିପ୍ ଡମ୍ପ ଉପଲବ୍ଧ ଅଛି। ସାବଧାନ ରୁହନ୍ତୁ: ଆପ୍ଲିକେଶନର ଆକ୍ସେସ୍ ରହିଥିବା ଆପଣଙ୍କର ଯେକୌଣସି ବ୍ୟକ୍ତିଗତ ସୂଚନା ଏହି ହିପ୍ ଡମ୍ପରେ ରହିପାରେ।"</string>
+ <string name="sendText" msgid="5209874571959469142">"ଟେକ୍ସଟ୍ ପାଇଁ ଏକ କାର୍ଯ୍ୟ ବାଛନ୍ତୁ"</string>
+ <string name="volume_ringtone" msgid="6885421406845734650">"ରିଙ୍ଗର୍ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_music" msgid="5421651157138628171">"ମିଡିଆ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"ବ୍ଲୁ-ଟୁଥ୍ ମାଧ୍ୟମରେ ଚାଲୁଛି"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"ରିଙ୍ଗଟୋନ୍କୁ ନିରବ ଭାବେ ସେଟ୍ କରାଯାଇଛି"</string>
+ <string name="volume_call" msgid="3941680041282788711">"ଇନ୍-କଲ୍ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_bluetooth_call" msgid="2002891926351151534">"ବ୍ଲୁ-ଟୁଥ୍ ଇନ୍-କଲ୍ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_alarm" msgid="1985191616042689100">"ଆଲାର୍ମର ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"ବିଜ୍ଞପ୍ତି ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_unknown" msgid="1400219669770445902">"ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"ବ୍ଲୁ-ଟୁଥ୍ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_icon_description_ringer" msgid="3326003847006162496">"ରିଙ୍ଗଟୋନ୍ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_icon_description_incall" msgid="8890073218154543397">"କଲ୍ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_icon_description_media" msgid="4217311719665194215">"ମିଡିଆ ଭଲ୍ୟୁମ୍"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"ବିଜ୍ଞପ୍ତି ଭଲ୍ୟୁମ୍"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"ଡିଫଲ୍ଟ ରିଙ୍ଗଟୋନ୍"</string>
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"ଡିଫଲ୍ଟ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent" msgid="7937634392408977062">"କିଛିନୁହେଁ"</string>
+ <string name="ringtone_picker_title" msgid="3515143939175119094">"ରିଙ୍ଗଟୋନ୍"</string>
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"ଆଲାର୍ମ ଶବ୍ଦ"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"ବିଜ୍ଞପ୍ତି ଶବ୍ଦ"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"ଅଜଣା"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କଗୁଡ଼ିକ ଉପଲବ୍ଧ</item>
+ <item quantity="one">ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ ଉପଲବ୍ଧ</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">ମୁକ୍ତ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କଗୁଡ଼ିକ ଉପଲବ୍ଧ</item>
+ <item quantity="one">ମୁକ୍ତ ୱାଇ-ଫାଇ ନେଟ୍ୱର୍କ ଉପଲବ୍ଧ</item>
+ </plurals>
+ <!-- no translation found for wifi_available_title (3817100557900599505) -->
+ <skip />
+ <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
+ <skip />
+ <!-- no translation found for wifi_available_title_connecting (1557292688310330032) -->
+ <skip />
+ <!-- no translation found for wifi_available_title_connected (7542672851522241548) -->
+ <skip />
+ <!-- no translation found for wifi_available_title_failed_to_connect (6861772233582618132) -->
+ <skip />
+ <!-- no translation found for wifi_available_content_failed_to_connect (3377406637062802645) -->
+ <skip />
+ <!-- no translation found for wifi_available_action_connect (2635699628459488788) -->
+ <skip />
+ <!-- no translation found for wifi_available_action_all_networks (4368435796357931006) -->
+ <skip />
+ <!-- no translation found for wifi_wakeup_onboarding_title (228772560195634292) -->
+ <skip />
+ <!-- no translation found for wifi_wakeup_onboarding_subtext (3989697580301186973) -->
+ <skip />
+ <!-- no translation found for wifi_wakeup_onboarding_action_disable (838648204200836028) -->
+ <skip />
+ <!-- no translation found for wifi_wakeup_enabled_title (6534603733173085309) -->
+ <skip />
+ <!-- no translation found for wifi_wakeup_enabled_content (189330154407990583) -->
+ <skip />
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ"</string>
+ <string name="network_available_sign_in" msgid="1848877297365446605">"ନେଟ୍ୱର୍କରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
+ <skip />
+ <!-- no translation found for wifi_no_internet (8938267198124654938) -->
+ <skip />
+ <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+ <!-- no translation found for network_switch_metered_detail (775163331794506615) -->
+ <skip />
+ <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+ <!-- no translation found for network_switch_type_name:0 (3979506840912951943) -->
+ <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ଏକ ଅଜଣା ନେଟ୍ୱର୍କ ପ୍ରକାର"</string>
+ <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ୱାଇ-ଫାଇ ସହ ସଂଯୋଗ ହୋଇପାରିଲା ନାହିଁ"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ଏହାର ଦୁର୍ବଳ ଇଣ୍ଟରନେଟ୍ ସଂଯୋଗ ରହିଛି।"</string>
+ <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ସଂଯୋଗର ଅନୁମତି ଦେବେ?"</string>
+ <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ଆପ୍ଲିକେଶନ୍ %1$s %2$s ୱାଇ-ଫାଇ ନେଟୱର୍କକୁ ସଂଯୋଗ କରିବାକୁ ଚାହେଁ"</string>
+ <string name="wifi_connect_default_application" msgid="7143109390475484319">"ଏକ ଅନୁପ୍ରୟୋଗ"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ ଆରମ୍ଭ କରନ୍ତୁ। ଏହା ୱାଇ-ଫାଇ କ୍ଲାଏଣ୍ଟ/ହଟସ୍ପଟ୍କୁ ବନ୍ଦ କରିଦେବ।"</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ ଆରମ୍ଭ କରିପାରିଲା ନାହିଁ।"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ ଅନ୍ ଅଛି"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ସେଟିଙ୍ଗ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="accept" msgid="1645267259272829559">"ସ୍ୱୀକାର କରନ୍ତୁ"</string>
+ <string name="decline" msgid="2112225451706137894">"ପ୍ରତ୍ୟାଖ୍ୟାନ"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ନିମନ୍ତ୍ରଣ ପଠାଗଲା"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ସଂଯୁକ୍ତ ହେବାକୁ ନିମନ୍ତ୍ରଣ"</string>
+ <string name="wifi_p2p_from_message" msgid="570389174731951769">"ପ୍ରେରକ:"</string>
+ <string name="wifi_p2p_to_message" msgid="248968974522044099">"ପ୍ରାପ୍ତେଷୁ:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ଆବଶ୍ୟକ PIN ଟାଇପ୍ କରନ୍ତୁ:"</string>
+ <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ ହୋଇଥିବାବେଳେ, ୱାଇ-ଫାଇଠାରୁ ଟାବଲେଟ୍ଟି ଅସ୍ଥାୟୀ ଭାବେ ବିଚ୍ଛିନ୍ନ ହେବ"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ହେବାବେଳେ ଟିଭି ଅସ୍ଥାୟୀ ଭାବେ ୱାଇ-ଫାଇରୁ ବିଚ୍ଛିନ୍ନ ହେବ"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ଥିବାବେଳେ ଫୋନ୍ଟି ୱାଇ-ଫାଇରୁ ଅସ୍ଥାୟୀ ଭାବରେ ବିଚ୍ଛିନ୍ନ ହେବ"</string>
+ <string name="select_character" msgid="3365550120617701745">"ବର୍ଣ୍ଣ ଲେଖନ୍ତୁ"</string>
+ <string name="sms_control_title" msgid="7296612781128917719">"SMS ମେସେଜ୍ଗୁଡ଼ିକୁ ପଠାଯାଉଛି"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ବହୁତ ସଂଖ୍ୟାର SMS ମେସେଜ୍ ପଠାଉଛି। ଏହି ଆପ୍ ମେସେଜ୍ ପଠାଇବା ଜାରି ରଖିବାକୁ ଆପଣ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"ପ୍ରତ୍ୟାଖ୍ୟାନ"</string>
+ <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>କୁ ଏକ ମେସେଜ୍ ପଠାଇବାକୁ ଚାହେଁ।"</string>
+ <string name="sms_short_code_details" msgid="5873295990846059400">"ଏହା ଦ୍ୱାରା "<b>" ଆପଣଙ୍କ ମୋବାଇଲ୍ ଆକାଉଣ୍ଟରୁ ପଇସା କଟିପାରେ। "</b></string>
+ <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>" ଆପଣଙ୍କ ମୋବାଇଲ୍ ଆକାଉଣ୍ଟରୁ ପଇସା କଟିପାରେ। "</b></string>
+ <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ପଠାନ୍ତୁ"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ମୋ ପସନ୍ଦ ମନେରଖନ୍ତୁ"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"ଏହାକୁ ଆପଣ ସେଟିଙ୍ଗ ଓ ଆପ୍ରେ ପରବର୍ତ୍ତୀ ସମୟରେ ବଦଳାଇପାରିବେ"</string>
+ <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"ସର୍ବଦା ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"ଆଦୌ ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"SIM କାର୍ଡ ବାହାର କରିଦିଆଯାଇଛି"</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"ଯେପର୍ଯ୍ୟନ୍ତ ଆପଣ କୌଣସି ବୈଧ SIM କାର୍ଡ ବ୍ୟବହାର କରି ରିଷ୍ଟାଟ୍ କରିନାହାନ୍ତି, ସେପର୍ଯ୍ୟନ୍ତ କୌଣସି ମୋବାଇଲ୍ ନେଟୱର୍କ ଉପଲବ୍ଧ ହେବନାହିଁ।"</string>
+ <string name="sim_done_button" msgid="827949989369963775">"ହୋଇଗଲା"</string>
+ <string name="sim_added_title" msgid="3719670512889674693">"SIM କାର୍ଡ ଯୋଡ଼ାଯାଇଛି"</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"ମୋବାଇଲ୍ ନେଟ୍ୱର୍କ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସ୍କୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
+ <string name="sim_restart_button" msgid="4722407842815232347">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
+ <!-- no translation found for install_carrier_app_notification_title (9056007111024059888) -->
+ <skip />
+ <!-- no translation found for install_carrier_app_notification_text (3346681446158696001) -->
+ <skip />
+ <!-- no translation found for install_carrier_app_notification_text_app_name (1196505084835248137) -->
+ <skip />
+ <!-- no translation found for install_carrier_app_notification_button (3094206295081900849) -->
+ <skip />
+ <!-- no translation found for carrier_app_notification_title (8921767385872554621) -->
+ <skip />
+ <!-- no translation found for carrier_app_notification_text (1132487343346050225) -->
+ <skip />
+ <string name="time_picker_dialog_title" msgid="8349362623068819295">"ସମୟ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="date_picker_dialog_title" msgid="5879450659453782278">"ତାରିଖ ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="date_time_set" msgid="5777075614321087758">"ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="date_time_done" msgid="2507683751759308828">"ହୋଇଗଲା"</string>
+ <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"ନୂଆ: "</font></string>
+ <string name="perms_description_app" msgid="5139836143293299417">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଦ୍ୱରା ପ୍ରଦତ୍ତ।"</string>
+ <string name="no_permissions" msgid="7283357728219338112">"କୌଣସି ଅନୁମତିର ଆବଶ୍ୟକତା ନାହିଁ"</string>
+ <string name="perm_costs_money" msgid="4902470324142151116">"ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ"</string>
+ <string name="dlg_ok" msgid="7376953167039865701">"ଠିକ୍ ଅଛି"</string>
+ <!-- no translation found for usb_charging_notification_title (1595122345358177163) -->
+ <skip />
+ <!-- no translation found for usb_supplying_notification_title (4631045789893086181) -->
+ <skip />
+ <!-- no translation found for usb_mtp_notification_title (4238227258391151029) -->
+ <skip />
+ <!-- no translation found for usb_ptp_notification_title (5425857879922006878) -->
+ <skip />
+ <!-- no translation found for usb_tether_notification_title (3716143122035802501) -->
+ <skip />
+ <!-- no translation found for usb_midi_notification_title (5356040379749154805) -->
+ <skip />
+ <!-- no translation found for usb_accessory_notification_title (1899977434994900306) -->
+ <skip />
+ <string name="usb_notification_message" msgid="3370903770828407960">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for usb_power_notification_message (4647527153291917218) -->
+ <skip />
+ <!-- no translation found for usb_unsupported_audio_accessory_title (3529881374464628084) -->
+ <skip />
+ <!-- no translation found for usb_unsupported_audio_accessory_message (6309553946441565215) -->
+ <skip />
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ଡିବଗିଙ୍ଗ ସଂଯୁକ୍ତ ହୋଇଛି"</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string>
+ <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_notification_title (4987095013583691873) -->
+ <skip />
+ <!-- no translation found for sharing_remote_bugreport_notification_title (7572089031496651372) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_notification_message_finished (6029609949340992866) -->
+ <skip />
+ <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
+ <skip />
+ <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
+ <skip />
+ <string name="select_input_method" msgid="8547250819326693584">"କୀ’ବୋର୍ଡ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+ <string name="show_ime" msgid="2506087537466597099">"ଫିଜିକାଲ୍ କୀ’ବୋର୍ଡ ସକ୍ରିୟ ଥିବାବେଳେ ଏହାକୁ ସ୍କ୍ରୀନ୍ ଉପରେ ରଖନ୍ତୁ"</string>
+ <string name="hardware" msgid="194658061510127999">"ଭର୍ଚୁଆଲ୍ କୀ’ବୋର୍ଡ ଦେଖାନ୍ତୁ"</string>
+ <!-- no translation found for select_keyboard_layout_notification_title (597189518763083494) -->
+ <skip />
+ <!-- no translation found for select_keyboard_layout_notification_message (8084622969903004900) -->
+ <skip />
+ <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <!-- no translation found for alert_windows_notification_channel_group_name (1463953341148606396) -->
+ <skip />
+ <!-- no translation found for alert_windows_notification_channel_name (3116610965549449803) -->
+ <skip />
+ <!-- no translation found for alert_windows_notification_title (3697657294867638947) -->
+ <skip />
+ <!-- no translation found for alert_windows_notification_message (8917232109522912560) -->
+ <skip />
+ <!-- no translation found for alert_windows_notification_turn_off_action (2902891971380544651) -->
+ <skip />
+ <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ପ୍ରସ୍ତୁତ କରାଯାଉଛି"</string>
+ <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ତ୍ରୁଟି ପାଇଁ ଯାଞ୍ଚ କରାଯାଉଛି"</string>
+ <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ନୂଆ <xliff:g id="NAME">%s</xliff:g> ଚିହ୍ନଟ ହେଲା"</string>
+ <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"ଫଟୋ ଓ ମିଡିଆ ସ୍ଥାନାନ୍ତର କରାଯିବା ପାଇଁ"</string>
+ <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"<xliff:g id="NAME">%s</xliff:g> କରପ୍ଟ ହୋଇଯାଇଛି"</string>
+ <string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"<xliff:g id="NAME">%s</xliff:g> କରପ୍ଟ ହୋଇଯାଇଛି। ଠିକ୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for ext_media_unmountable_notification_message (3941179940297874950) -->
+ <skip />
+ <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"ଏହି ଡିଭାଇସ୍ ଏହି <xliff:g id="NAME">%s</xliff:g>କୁ ସପୋର୍ଟ କରେନାହିଁ। ଗୋଟିଏ ସପୋର୍ଟ କରୁଥିବା ଫର୍ମାଟ୍ରେ ସେଟ୍ ଅପ୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for ext_media_unsupported_notification_message (3725436899820390906) -->
+ <skip />
+ <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"<xliff:g id="NAME">%s</xliff:g>କୁ ହଠାତ୍ କାଢ଼ିଦିଆଗଲା"</string>
+ <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"ଡାଟା ନଷ୍ଟ ନହେବା ପାଇଁ ବାହାର କରିବା ପୂର୍ବରୁ <xliff:g id="NAME">%s</xliff:g>କୁ ଅନ୍ମାଉଣ୍ଟ କରନ୍ତୁ"</string>
+ <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"<xliff:g id="NAME">%s</xliff:g> କାଢ଼ିଦିଆଗଲା"</string>
+ <string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"<xliff:g id="NAME">%s</xliff:g> ବାହାର କରାଗଲା; ନୂଆ ଗୋଟିଏ ଭର୍ତ୍ତି କରନ୍ତୁ"</string>
+ <string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"<xliff:g id="NAME">%s</xliff:g> ଏପର୍ଯ୍ୟନ୍ତ ବାହାର କରାଯାଉଛି…"</string>
+ <string name="ext_media_unmounting_notification_message" msgid="4182843895023357756">"କାଢ଼ନ୍ତୁ ନାହିଁ"</string>
+ <string name="ext_media_init_action" msgid="7952885510091978278">"ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
+ <string name="ext_media_unmount_action" msgid="1121883233103278199">"ବାହାର କରନ୍ତୁ"</string>
+ <string name="ext_media_browse_action" msgid="8322172381028546087">"ଖୋଜନ୍ତୁ"</string>
+ <string name="ext_media_missing_title" msgid="620980315821543904">"<xliff:g id="NAME">%s</xliff:g> ନାହିଁ"</string>
+ <string name="ext_media_missing_message" msgid="5761133583368750174">"ଏହି ଡିଭାଇସ୍ ପୁଣି ଭର୍ତ୍ତି କରନ୍ତୁ"</string>
+ <string name="ext_media_move_specific_title" msgid="1471100343872375842">"<xliff:g id="NAME">%s</xliff:g> ନିଆଯାଉଛି"</string>
+ <string name="ext_media_move_title" msgid="1022809140035962662">"ଡାଟା ନିଆଯାଉଛି"</string>
+ <string name="ext_media_move_success_title" msgid="8575300932957954671">"ନେବା ସମ୍ପୂର୍ଣ୍ଣ ହେଲା"</string>
+ <string name="ext_media_move_success_message" msgid="4199002148206265426">"ଡାଟା <xliff:g id="NAME">%s</xliff:g>କୁ ନିଆଗଲା"</string>
+ <string name="ext_media_move_failure_title" msgid="7613189040358789908">"ଡାଟା ନିଆଯାଇପାରିଲା ନାହିଁ"</string>
+ <string name="ext_media_move_failure_message" msgid="1978096440816403360">"ଡାଟାକୁ ମୂଳ ଲୋକେଶନରେ ଛାଡ଼ିଦିଆଗଲା"</string>
+ <string name="ext_media_status_removed" msgid="6576172423185918739">"ବାହାର କରିଦିଆଗଲା"</string>
+ <string name="ext_media_status_unmounted" msgid="2551560878416417752">"ବାହାର କରାଗଲା"</string>
+ <string name="ext_media_status_checking" msgid="6193921557423194949">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
+ <string name="ext_media_status_mounted" msgid="7253821726503179202">"ପ୍ରସ୍ତୁତ"</string>
+ <string name="ext_media_status_mounted_ro" msgid="8020978752406021015">"କେବଳ-ପଢ଼ିବା ପାଇଁ"</string>
+ <string name="ext_media_status_bad_removal" msgid="8395398567890329422">"ଅସୁରକ୍ଷିତ ଭାବେ କାଢ଼ିଦିଆଗଲା"</string>
+ <string name="ext_media_status_unmountable" msgid="805594039236667894">"କରପ୍ଟ ହୋଇଯାଇଛି"</string>
+ <string name="ext_media_status_unsupported" msgid="4691436711745681828">"ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="ext_media_status_ejecting" msgid="5463887263101234174">"ବାହାର କରାଯାଉଛି…"</string>
+ <string name="ext_media_status_formatting" msgid="1085079556538644861">"ଫର୍ମାଟ୍ କରାଯାଉଛି…"</string>
+ <string name="ext_media_status_missing" msgid="5638633895221670766">"ଭର୍ତ୍ତି କରାଯାଇନାହିଁ"</string>
+ <string name="activity_list_empty" msgid="1675388330786841066">"କୌଣସି ଗତିବିଧି ମେଳ ହେଉନାହିଁ।"</string>
+ <string name="permlab_route_media_output" msgid="6243022988998972085">"ମିଡିଆ ଆଉଟପୁଟ୍କୁ ରୁଟ୍ କରନ୍ତୁ"</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"ମିଡିଆ ଆଉଟ୍ପୁଟ୍କୁ ଅନ୍ୟ ଏକ୍ସଟର୍ନଲ୍ ଡିଭାଇସ୍ରେ ଚଲାଇବା ପାଇଁ ଆପ୍ଲିକେଶନ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_readInstallSessions" msgid="3713753067455750349">"ଇନଷ୍ଟଲ୍ ସେସନ୍ ପଢ଼ନ୍ତୁ"</string>
+ <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"ଅନୁପ୍ରୟୋଗର ଇନଷ୍ଟଲ୍ ଅବଧିକୁ ପଢିବାକୁ ଅନୁମତି ଦେଇଥାଏ। ଏହି ସକ୍ରିୟ ପ୍ୟାକେଜ୍କୁ ଇନଷ୍ଟଲ୍ ବିଷୟରେ ବିବରଣୀ ଦେଖିବାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"ପ୍ୟାକେଜ୍ ଇନଷ୍ଟଲ୍ କରିବା ପାଇଁ ଅନୁରୋଧ କରନ୍ତୁ"</string>
+ <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"ପ୍ୟାକେଜଗୁଡ଼ିକର ଇନଷ୍ଟଲେଶନ୍ ଅନୁରୋଧ କରିବା ପାଇଁ ଆପ୍ଲିକେଶନକୁ ଅନୁମତି ଦିଏ।"</string>
+ <!-- no translation found for permlab_requestDeletePackages (1703686454657781242) -->
+ <skip />
+ <!-- no translation found for permdesc_requestDeletePackages (3406172963097595270) -->
+ <skip />
+ <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"ବ୍ୟାଟେରୀ ଅନୁକୂଳନ ଏଡ଼ାଇବା ପାଇଁ ପଚାରନ୍ତୁ"</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"ଆପ୍ ପାଇଁ ବ୍ୟାଟେରୀ ଅନୁକୂଳନ ଏଡ଼ାଇବାର ଅନୁମତି ମାଗିବା ନିମନ୍ତେ ଆପ୍କୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ଜୁମ୍ ନିୟନ୍ତ୍ରଣ ପାଇଁ ଦୁଇଥର ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="gadget_host_error_inflating" msgid="4882004314906466162">"ୱିଜେଟ୍ ଯୋଡ଼ିପାରିବ ନାହିଁ।"</string>
+ <string name="ime_action_go" msgid="8320845651737369027">"ଯାଆନ୍ତୁ"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <string name="ime_action_send" msgid="2316166556349314424">"ପଠାନ୍ତୁ"</string>
+ <string name="ime_action_next" msgid="3138843904009813834">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="ime_action_done" msgid="8971516117910934605">"ହୋଇଗଲା"</string>
+ <string name="ime_action_previous" msgid="1443550039250105948">"ପୂର୍ବବର୍ତ୍ତୀ"</string>
+ <string name="ime_action_default" msgid="2840921885558045721">"କାମ କରନ୍ତୁ"</string>
+ <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>ବ୍ୟବହାର କରି\n ଡାଏଲ୍ କରନ୍ତୁ"</string>
+ <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>ବ୍ୟବହାର କରି\n ଯୋଗାଯୋଗ ତିଆରି କରନ୍ତୁ"</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"ବର୍ତ୍ତମାନ ଓ ଭବିଷ୍ୟତରେ ଆପଣଙ୍କ ଆକାଉଣ୍ଟ ଆକ୍ସେସ୍ କରିବାକୁ ନିମ୍ନରୁ ଗୋଟିଏ କିମ୍ବା ଅଧିକ ଆପ୍ ଅନୁମତି ଅନୁରୋଧ କରନ୍ତି।"</string>
+ <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"ଆପଣ ଏହି ଅନୁରୋଧକୁ ଅନୁମତି ଦେବାକୁ ଚାହାଁନ୍ତି କି?"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"ଆକ୍ସେସ୍ ଅନୁରୋଧ"</string>
+ <string name="allow" msgid="7225948811296386551">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+ <string name="deny" msgid="2081879885755434506">"ପ୍ରତ୍ୟାଖ୍ୟାନ"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"ଅନୁମତି ଅନୁରୋଧ କରାଯାଇଛି"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> ଆକାଉଣ୍ଟ ପାଇଁ ଅନୁମତି\n ଅନୁରୋଧ କରାଯାଇଛି।"</string>
+ <string name="forward_intent_to_owner" msgid="1207197447013960896">"ଆପଣ ନିଜର ୱର୍କ ପ୍ରୋଫାଇଲ୍ ବାହାରେ ଏହି ଆପ୍ର ପ୍ରୟୋଗ କରୁଛନ୍ତି"</string>
+ <string name="forward_intent_to_work" msgid="621480743856004612">"ଆପଣ ନିଜ ୱର୍କ ପ୍ରୋଫାଇଲ୍ରେ ଏହି ଆପ୍ର ବ୍ୟବହାର କରୁଛନ୍ତି"</string>
+ <string name="input_method_binding_label" msgid="1283557179944992649">"ଇନପୁଟ୍ ପଦ୍ଧତି"</string>
+ <string name="sync_binding_label" msgid="3687969138375092423">"ସିଙ୍କ୍"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"ଆକ୍ସେସିବିଲିଟୀ"</string>
+ <string name="wallpaper_binding_label" msgid="1240087844304687662">"ୱାଲପେପର୍"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"ୱାଲପେପର୍ ପରିବର୍ତ୍ତନ କରନ୍ତୁ।"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"ବିଜ୍ଞପ୍ତି ଶ୍ରୋତା"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
+ <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ସର୍ତ୍ତ ପ୍ରଦାତା"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
+ <string name="vpn_title" msgid="19615213552042827">"VPN ସକ୍ରିୟ ହେଲା"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ଦ୍ୱାରା VPN ସକ୍ରିୟ କରାଯାଇଛି"</string>
+ <string name="vpn_text" msgid="1610714069627824309">"ନେଟ୍ୱର୍କକୁ ପରିଚାଳନା କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>ରେ ସଂଯୋଗ କରାଯାଇଛି। ନେଟୱର୍କକୁ ପରିଚାଳନା କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ସର୍ବଦା-ଅନ୍ VPNରେ ସଂଯୋଗ କରୁଛି…"</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ସର୍ବଦା-ଅନ୍ VPN ସଂଯୁକ୍ତ"</string>
+ <!-- no translation found for vpn_lockdown_disconnected (735805531187559719) -->
+ <skip />
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"ସର୍ବଦା-ଅନ୍ VPN ତ୍ରୁଟି"</string>
+ <!-- no translation found for vpn_lockdown_config (8151951501116759194) -->
+ <skip />
+ <string name="upload_file" msgid="2897957172366730416">"ଫାଇଲ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"କୌଣସି ଫାଇଲ୍ ଚୟନ କରାଯାଇନାହିଁ"</string>
+ <string name="reset" msgid="2448168080964209908">"ରିସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="submit" msgid="1602335572089911941">"ଦାଖଲ କରନ୍ତୁ"</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"କାର୍ ମୋଡ୍ ସକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"କାର୍ ମୋଡ୍ରୁ ବାହାରିଯିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ସେଟଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for disable_tether_notification_title (7526977944111313195) -->
+ <skip />
+ <!-- no translation found for disable_tether_notification_message (2913366428516852495) -->
+ <skip />
+ <string name="back_button_label" msgid="2300470004503343439">"ଫେରନ୍ତୁ"</string>
+ <string name="next_button_label" msgid="1080555104677992408">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="skip_button_label" msgid="1275362299471631819">"ଛାଡ଼ିଦିଅନ୍ତୁ"</string>
+ <string name="no_matches" msgid="8129421908915840737">"କୌଣସି ମେଳକ ନାହିଁ"</string>
+ <string name="find_on_page" msgid="1946799233822820384">"ପୃଷ୍ଠାରେ ଖୋଜନ୍ତୁ"</string>
+ <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+ <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g>ରୁ <xliff:g id="INDEX">%d</xliff:g></item>
+ <item quantity="one">1ଟି ମେଳ</item>
+ </plurals>
+ <string name="action_mode_done" msgid="7217581640461922289">"ହୋଇଗଲା"</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"USB ଷ୍ଟୋରେଜ୍ ଲିଭାଯାଉଛି…"</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"SD କାର୍ଡ ଲିଭାଯାଉଛି…"</string>
+ <string name="share" msgid="1778686618230011964">"ଶେୟାର୍"</string>
+ <string name="find" msgid="4808270900322985960">"ଖୋଜନ୍ତୁ"</string>
+ <string name="websearch" msgid="4337157977400211589">"ୱେବ୍ ସର୍ଚ୍ଚ"</string>
+ <string name="find_next" msgid="5742124618942193978">"ପରବର୍ତ୍ତୀ ଖୋଜନ୍ତୁ"</string>
+ <string name="find_previous" msgid="2196723669388360506">"ପୂର୍ବବର୍ତ୍ତୀ ଖୋଜନ୍ତୁ"</string>
+ <string name="gpsNotifTicker" msgid="5622683912616496172">"<xliff:g id="NAME">%s</xliff:g>ଙ୍କଠାରୁ ଲୋକେଶନ୍ ଅନୁରୋଧ ଆସିଛି"</string>
+ <string name="gpsNotifTitle" msgid="5446858717157416839">"ଲୋକେଶନ୍ ଅନୁରୋଧ"</string>
+ <string name="gpsNotifMessage" msgid="1374718023224000702">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)ଙ୍କ ଦ୍ୱାରା ଅନୁରୋଧ କରାଯାଇଛି"</string>
+ <string name="gpsVerifYes" msgid="2346566072867213563">"ହଁ"</string>
+ <string name="gpsVerifNo" msgid="1146564937346454865">"ନା"</string>
+ <string name="sync_too_many_deletes" msgid="5296321850662746890">"ଡିଲିଟ୍ କରିବାର ସୀମା ଅତିକ୍ରମ ହୋଇଯାଇଛି"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"<xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> ଆକାଉଣ୍ଟର <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> ପାଇଁ <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> ଟି ଡିଲିଟ୍ କରାଯାଇଥିବା ଆଇଟମ୍ ରହିଛି। ଆପଣ କ’ଣ କରିବାକୁ ଚାହାଁନ୍ତି?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"ଆଇଟମ୍ ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"ଡିଲିଟ୍ଗୁଡ଼ିକୁ ପୂର୍ବାବସ୍ଥାକୁ ଫେରାଇ ଆଣନ୍ତୁ"</string>
+ <string name="sync_do_nothing" msgid="3743764740430821845">"ଏବେ କିଛି କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"ଗୋଟିଏ ଆକାଉଣ୍ଟର ଚୟନ କରନ୍ତୁ"</string>
+ <string name="add_account_label" msgid="2935267344849993553">"ଗୋଟିଏ ଆକାଉଣ୍ଟ ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="add_account_button_label" msgid="3611982894853435874">"ଆକାଉଣ୍ଟ ଯୋଡ଼ନ୍ତୁ"</string>
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"ବଢ଼ାନ୍ତୁ"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"କମ୍ କରନ୍ତୁ"</string>
+ <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଧରିରଖନ୍ତୁ"</string>
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"ବଢ଼ାଇବା ପାଇଁ ଉପରକୁ ଓ କମାଇବା ପାଇଁ ତଳକୁ ସ୍ଲାଇଡ୍ କରନ୍ତୁ।"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"ମିନିଟ୍ ବଢ଼ାନ୍ତୁ"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"ମିନିଟ୍ କମ୍ କରନ୍ତୁ"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"ଘଣ୍ଟା ବଢ଼ାନ୍ତୁ"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"ଘଣ୍ଟା କମ୍ କରନ୍ତୁ"</string>
+ <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"PM ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"AM ସେଟ୍ କରନ୍ତୁ"</string>
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"ମାସ ବଢ଼ାନ୍ତୁ"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"ମାସ କମ୍ କରନ୍ତୁ"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"ଦିନ ବଢ଼ାନ୍ତୁ"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ଦିନ କମ୍ କରନ୍ତୁ"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ବର୍ଷ ବଢ଼ାନ୍ତୁ"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ବର୍ଷ କମ୍ କରନ୍ତୁ"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ପୂର୍ବ ମାସ"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"ପରବର୍ତ୍ତୀ ମାସ"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"ALT"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ହୋଇଗଲା"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ମୋଡ୍ ପରିବର୍ତ୍ତନ"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ଶିଫ୍ଟ"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ଏଣ୍ଟର୍"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ଗୋଟିଏ ଆପ୍ ବାଛନ୍ତୁ"</string>
+ <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ଲଞ୍ଚ କରାଯାଇପାରିଲା ନାହିଁ"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"ଏହାଙ୍କ ସହ ଶେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ସହ ଶେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"ହ୍ୟାଣ୍ଡେଲ୍ ସ୍ଲାଇଡ୍ କରାଯାଉଛି। ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ।"</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"ଅନଲକ୍ କରିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ।"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"ହୋମ୍ ପେଜ୍କୁ ନେଭିଗେଟ୍ କରନ୍ତୁ"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"ଉପରକୁ ନେଭିଗେଟ୍ କରନ୍ତୁ"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"ଅଧିକ ବିକଳ୍ପ"</string>
+ <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
+ <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
+ <!-- no translation found for storage_internal (3570990907910199483) -->
+ <skip />
+ <string name="storage_sd_card" msgid="3282948861378286745">"SD କାର୍ଡ"</string>
+ <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD କାର୍ଡ"</string>
+ <string name="storage_usb_drive" msgid="6261899683292244209">"USB ଡ୍ରାଇଭ୍"</string>
+ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ଡ୍ରାଇଭ୍"</string>
+ <string name="storage_usb" msgid="3017954059538517278">"USB ଷ୍ଟୋରେଜ୍"</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for data_usage_warning_title (6499834033204801605) -->
+ <skip />
+ <!-- no translation found for data_usage_warning_body (7340198905103751676) -->
+ <skip />
+ <!-- no translation found for data_usage_mobile_limit_title (6561099244084267376) -->
+ <skip />
+ <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"ୱାଇ-ଫାଇ ଡାଟା ସୀମାରେ ପହଞ୍ଚିଗଲା"</string>
+ <!-- no translation found for data_usage_limit_body (2908179506560812973) -->
+ <skip />
+ <!-- no translation found for data_usage_mobile_limit_snoozed_title (3171402244827034372) -->
+ <skip />
+ <!-- no translation found for data_usage_wifi_limit_snoozed_title (3547771791046344188) -->
+ <skip />
+ <!-- no translation found for data_usage_limit_snoozed_body (1671222777207603301) -->
+ <skip />
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"ବ୍ୟାକଗ୍ରାଉଣ୍ଡ ଡାଟା ପ୍ରତିବନ୍ଧିତ"</string>
+ <string name="data_usage_restricted_body" msgid="469866376337242726">"ପ୍ରତିବନ୍ଧକ ବାହାର କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for data_usage_rapid_title (1809795402975261331) -->
+ <skip />
+ <!-- no translation found for data_usage_rapid_body (6897825788682442715) -->
+ <skip />
+ <!-- no translation found for data_usage_rapid_app_body (5396680996784142544) -->
+ <skip />
+ <string name="ssl_certificate" msgid="6510040486049237639">"ସୁରକ୍ଷା ସର୍ଟିଫିକେଟ୍"</string>
+ <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"ସର୍ଟିଫିକେଟ୍ ବୈଧ ନୁହେଁ।"</string>
+ <string name="issued_to" msgid="454239480274921032">"ଏହାଙ୍କୁ ଜାରି କରାଯାଇଛି:"</string>
+ <string name="common_name" msgid="2233209299434172646">"ସାଧାରଣ ନାମ:"</string>
+ <string name="org_name" msgid="6973561190762085236">"ସଂସ୍ଥା:"</string>
+ <string name="org_unit" msgid="7265981890422070383">"ସଂଗଠନାତ୍ମକ ୟୁନିଟ୍:"</string>
+ <string name="issued_by" msgid="2647584988057481566">"ଜାରି କରିଛନ୍ତି:"</string>
+ <string name="validity_period" msgid="8818886137545983110">"ବୈଧତା:"</string>
+ <string name="issued_on" msgid="5895017404361397232">"ଜାରି କରାଯାଇଥିବା ତାରିଖ:"</string>
+ <string name="expires_on" msgid="3676242949915959821">"ସମାପ୍ତ ହେବାର ତାରିଖ ହେଉଛି:"</string>
+ <string name="serial_number" msgid="758814067660862493">"କ୍ରମିକ ସଂଖ୍ୟା:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"ଆଙ୍ଗୁଠି ଚିହ୍ନ:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 ଆଙ୍ଗୁଠି ଚିହ୍ନ:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 ଆଙ୍ଗୁଠି ଚିହ୍ନ:"</string>
+ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"ସମସ୍ତ ଦେଖନ୍ତୁ"</string>
+ <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"ଗତିବିଧି ଚୟନ କରନ୍ତୁ"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"ଏହାଙ୍କ ସହ ଶେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="sending" msgid="3245653681008218030">"ପଠାଯାଉଛି…"</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"ବ୍ରାଉଜର୍ ଲଞ୍ଚ କରିବେ?"</string>
+ <string name="SetupCallDefault" msgid="5834948469253758575">"କଲ୍ ସ୍ୱୀକାର କରିବେ?"</string>
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"ସର୍ବଦା"</string>
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"ଥରେ ମାତ୍ର"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ୱର୍କ ପ୍ରୋଫାଇଲ୍କୁ ସପୋର୍ଟ କରୁନାହିଁ"</string>
+ <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ଟାବଲେଟ୍"</string>
+ <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
+ <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"ଫୋନ୍"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ଡକ୍ ସ୍ପିକର୍"</string>
+ <!-- no translation found for default_audio_route_name_hdmi (1486254205617081251) -->
+ <skip />
+ <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"ହେଡଫୋନ୍"</string>
+ <!-- no translation found for default_audio_route_name_usb (1234984851352637769) -->
+ <skip />
+ <string name="default_audio_route_category_name" msgid="3722811174003886946">"ସିଷ୍ଟମ୍"</string>
+ <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ବ୍ଲୁ-ଟୁଥ୍ ଅଡିଓ"</string>
+ <string name="wireless_display_route_description" msgid="9070346425023979651">"ୱେୟାର୍ଲେସ୍ ଡିସ୍ପ୍ଲେ"</string>
+ <string name="media_route_button_content_description" msgid="591703006349356016">"କାଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"ଡିଭାଇସ୍ ସଂଯୋଗ କରନ୍ତୁ"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ଡିଭାଇସ୍ରେ ସ୍କ୍ରୀନ୍ କାଷ୍ଟ କରନ୍ତୁ"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"ଡିଭାଇସ୍ ଖୋଜାଯାଉଛି…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ସେଟିଙ୍ଗ"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ବିଛିନ୍ନ କରନ୍ତୁ"</string>
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"ସ୍କାନ୍ କରୁଛି…"</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"ସଂଯୋଗ କରୁଛି..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"ଉପଲବ୍ଧ"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="media_route_status_in_use" msgid="4533786031090198063">"ବ୍ୟବହାରରେ ଅଛି"</string>
+ <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"ବିଲ୍ଟ-ଇନ୍ ସ୍କ୍ରୀନ୍"</string>
+ <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI ସ୍କ୍ରୀନ୍"</string>
+ <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ପ୍ରାୟତଃ #<xliff:g id="ID">%1$d</xliff:g>"</string>
+ <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<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="6022119702628572080">", ସୁରକ୍ଷିତ"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ପାଟର୍ନ ଭୁଲି ଯାଇଛନ୍ତି"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"ଭୁଲ ପାଟର୍ନ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"ଭୁଲ ପାସ୍ୱର୍ଡ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"ଭୁଲ PIN"</string>
+ <!-- no translation found for kg_too_many_failed_attempts_countdown (8790651267324125694) -->
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"ନିଜ ପାଟର୍ନ ଆଙ୍କନ୍ତୁ"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN ଲେଖନ୍ତୁ"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN ଲେଖନ୍ତୁ"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"ପାସ୍ୱର୍ଡ ଲେଖନ୍ତୁ"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM ବର୍ତ୍ତମାନ ଅକ୍ଷମ ଅଟେ। ଜାରି ରଖିବାକୁ PUK କୋଡ୍ ଏଣ୍ଟର୍ କରନ୍ତୁ। ବିବରଣୀ ପାଇଁ ନିଜ କେରିଅର୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"ନିଜ ଇଚ୍ଛାର PIN କୋଡ୍ ଲେଖନ୍ତୁ"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"ନିଜ ଇଚ୍ଛାର PIN କୋଡ୍ ନିଶ୍ଚିତ କରନ୍ତୁ"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM କାର୍ଡ ଅନଲକ୍ କରାଯାଉଛି…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ଭୁଲ PIN କୋଡ୍।"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4 ରୁ 8 ନମ୍ବର ବିଶିଷ୍ଟ ଏକ PIN ଟାଇପ୍ କରନ୍ତୁ।"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK କୋଡ୍ରେ 8ଟି ନମ୍ବର ରହିଥାଏ।"</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"ଠିକ୍ PUK କୋଡ୍ ପୁଣି ଲେଖନ୍ତୁ। ବାରମ୍ବାର ପ୍ରୟାସ କଲେ SIM କାର୍ଡ ସ୍ଥାୟୀ ରୂପେ ଅକ୍ଷମ ହୋଇଯିବ।"</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN କୋଡ୍ ମେଳ ଖାଉନାହିଁ"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ଅନେକ ପାଟର୍ନ ପ୍ରୟାସ"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"ଅନଲକ୍ କରିବା ପାଇଁ, ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟ ସହ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ।"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"ୟୁଜରନେମ୍ (ଇମେଲ୍)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ପାସ୍ୱର୍ଡ"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"ସାଇନ୍-ଇନ୍"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"ଅମାନ୍ୟ ୟୁଜରନେମ୍ କିମ୍ୱା ପାସ୍ୱର୍ଡ।"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ଆପଣଙ୍କର ୟୁଜରନେମ୍ କିମ୍ୱା ପାସ୍ୱର୍ଡ ଭୁଲି ଯାଇଛନ୍ତି କି?\n"<b>"google.com/accounts/recovery"</b>" ଭିଜିଟ୍ କରନ୍ତୁ।"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"ଆକାଉଣ୍ଟ ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ଆପଣଙ୍କ PINକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। <xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ \n\nପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ଆପଣଙ୍କ ପାସ୍ୱର୍ଡକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। <xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ \n\nପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ଆପଣଙ୍କ ଲକ୍ ଖୋଲିବା ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। <xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ \n\nପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"ଟାବଲେଟ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ, ଟାବଲେଟ୍ଟି ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ ଏବଂ ସମସ୍ତ ୟୁଜର୍ ଡାଟା ବାହାରିଯିବ।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"ଟିଭିଟିକୁ ଅନଲକ୍ କରିବା ପାଇଁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ୍ ପ୍ରୟାସ କଲେ। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ୍ ପ୍ରୟାସ ପରେ, ଟିଭିଟି ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ ଏବଂ ସମସ୍ତ ୟୁଜର୍ ଡାଟା ବାହାରିଯିବ।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"ଫୋନ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ, ଫୋନ୍ଟି ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ ଏବଂ ସମସ୍ତ ୟୁଜର୍ ଡାଟା ବାହାରିଯିବ।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"ଟାବଲେଟ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଟାବଲେଟ୍ଟି ବର୍ତ୍ତମାନ ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"ଟିଭିକୁ ଅନଲକ୍ କରିବା ପାଇଁ ଆପଣ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ୍ ପ୍ରୟାସ କଲେ। ଟିଭିଟି ବର୍ତ୍ତମାନ ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ।"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"ଫୋନ୍ ଅନଲକ୍ କରିବାକୁ ଆପଣ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ ପ୍ରୟାସ କଲେ। ଫୋନ୍ଟି ବର୍ତ୍ତମାନ ଫ୍ୟାକ୍ଟୋରୀ ଡିଫଲ୍ଟକୁ ରିସେଟ୍ ହୋଇଯିବ।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <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="tv" msgid="4224651132862313471">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <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="1437638152015574839">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <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="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ବାହାର କରନ୍ତୁ"</string>
+ <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିସ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string>
+ <!-- no translation found for accessibility_shortcut_warning_dialog_title (8404780875025725199) -->
+ <skip />
+ <!-- no translation found for accessibility_shortcut_toogle_warning (7256507885737444807) -->
+ <skip />
+ <!-- no translation found for disable_accessibility_shortcut (627625354248453445) -->
+ <skip />
+ <!-- no translation found for leave_accessibility_shortcut_on (7653111894438512680) -->
+ <skip />
+ <!-- no translation found for color_inversion_feature_name (4231186527799958644) -->
+ <skip />
+ <!-- no translation found for color_correction_feature_name (6779391426096954933) -->
+ <skip />
+ <!-- no translation found for accessibility_shortcut_enabling_service (7771852911861522636) -->
+ <skip />
+ <!-- no translation found for accessibility_shortcut_disabling_service (2747243438223109821) -->
+ <skip />
+ <!-- no translation found for accessibility_button_prompt_text (4234556536456854251) -->
+ <skip />
+ <!-- no translation found for accessibility_button_instructional_text (6942300463612999993) -->
+ <skip />
+ <!-- no translation found for accessibility_magnification_chooser_text (1227146738764986237) -->
+ <skip />
+ <string name="user_switched" msgid="3768006783166984410">"ବର୍ତ୍ତମାନର ୟୁଜର୍ ହେଉଛନ୍ତି <xliff:g id="NAME">%1$s</xliff:g>।"</string>
+ <string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> ରେ ସୁଇଚ୍ କରନ୍ତୁ…"</string>
+ <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g>ଙ୍କୁ ଲଗଆଉଟ୍ କରାଯାଉଛି…"</string>
+ <string name="owner_name" msgid="2716755460376028154">"ମାଲିକ"</string>
+ <string name="error_message_title" msgid="4510373083082500195">"ତ୍ରୁଟି"</string>
+ <!-- no translation found for error_message_change_not_allowed (1238035947357923497) -->
+ <skip />
+ <string name="app_not_found" msgid="3429141853498927379">"ଏହି କାର୍ଯ୍ୟକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ କୌଣସି ଆପ୍ଲିକେଶନ୍ ମିଳିଲା ନାହିଁ"</string>
+ <string name="revoke" msgid="5404479185228271586">"ବାହାର କରନ୍ତୁ"</string>
+ <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
+ <string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
+ <string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
+ <string name="mediasize_iso_a3" msgid="3023213259314236123">"ISO A3"</string>
+ <string name="mediasize_iso_a4" msgid="231745325296873764">"ISO A4"</string>
+ <string name="mediasize_iso_a5" msgid="3484327407340865411">"ISO A5"</string>
+ <string name="mediasize_iso_a6" msgid="4861908487129577530">"ISO A6"</string>
+ <string name="mediasize_iso_a7" msgid="5890208588072936130">"ISO A7"</string>
+ <string name="mediasize_iso_a8" msgid="4319425041085816612">"ISO A8"</string>
+ <string name="mediasize_iso_a9" msgid="4882220529506432008">"ISO A9"</string>
+ <string name="mediasize_iso_a10" msgid="2382866026365359391">"ISO A10"</string>
+ <string name="mediasize_iso_b0" msgid="3651827147402009675">"ISO B0"</string>
+ <string name="mediasize_iso_b1" msgid="6072859628278739957">"ISO B1"</string>
+ <string name="mediasize_iso_b2" msgid="1348731852150380378">"ISO B2"</string>
+ <string name="mediasize_iso_b3" msgid="2612510181259261379">"ISO B3"</string>
+ <string name="mediasize_iso_b4" msgid="695151378838115434">"ISO B4"</string>
+ <string name="mediasize_iso_b5" msgid="4863754285582212487">"ISO B5"</string>
+ <string name="mediasize_iso_b6" msgid="5305816292139647241">"ISO B6"</string>
+ <string name="mediasize_iso_b7" msgid="531673542602786624">"ISO B7"</string>
+ <string name="mediasize_iso_b8" msgid="9164474595708850034">"ISO B8"</string>
+ <string name="mediasize_iso_b9" msgid="282102976764774160">"ISO B9"</string>
+ <string name="mediasize_iso_b10" msgid="4517141714407898976">"ISO B10"</string>
+ <string name="mediasize_iso_c0" msgid="3103521357901591100">"ISO C0"</string>
+ <string name="mediasize_iso_c1" msgid="1231954105985048595">"ISO C1"</string>
+ <string name="mediasize_iso_c2" msgid="927702816980087462">"ISO C2"</string>
+ <string name="mediasize_iso_c3" msgid="835154173518304159">"ISO C3"</string>
+ <string name="mediasize_iso_c4" msgid="5095951985108194011">"ISO C4"</string>
+ <string name="mediasize_iso_c5" msgid="1985397450332305739">"ISO C5"</string>
+ <string name="mediasize_iso_c6" msgid="8147421924174693013">"ISO C6"</string>
+ <string name="mediasize_iso_c7" msgid="8993994925276122950">"ISO C7"</string>
+ <string name="mediasize_iso_c8" msgid="6871178104139598957">"ISO C8"</string>
+ <string name="mediasize_iso_c9" msgid="7983532635227561362">"ISO C9"</string>
+ <string name="mediasize_iso_c10" msgid="5040764293406765584">"ISO C10"</string>
+ <string name="mediasize_na_letter" msgid="2841414839888344296">"ଲେଟର୍"</string>
+ <string name="mediasize_na_gvrnmt_letter" msgid="5295836838862962809">"ସରକାରୀ ଲେଟର୍"</string>
+ <string name="mediasize_na_legal" msgid="8621364037680465666">"ଲିଗାଲ"</string>
+ <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"ଜୁନିଅର୍ ଲିଗାଲ୍"</string>
+ <string name="mediasize_na_ledger" msgid="5567030340509075333">"ଲେଜର୍"</string>
+ <string name="mediasize_na_tabloid" msgid="4571735038501661757">"ଟାବଲୋଏଡ୍"</string>
+ <string name="mediasize_na_index_3x5" msgid="5182901917818625126">"ଇଣ୍ଡେକ୍ସ କାର୍ଡ 3x5"</string>
+ <string name="mediasize_na_index_4x6" msgid="7687620625422312396">"ଇଣ୍ଡେକ୍ସ କାର୍ଡ 4x6"</string>
+ <string name="mediasize_na_index_5x8" msgid="8834215284646872800">"ଇଣ୍ଡେକ୍ସ କାର୍ଡ 5x8"</string>
+ <string name="mediasize_na_monarch" msgid="213639906956550754">"ମୋନାର୍କ"</string>
+ <string name="mediasize_na_quarto" msgid="835778493593023223">"କ୍ୱାର୍ଟୋ"</string>
+ <string name="mediasize_na_foolscap" msgid="1573911237983677138">"Foolscap"</string>
+ <string name="mediasize_chinese_roc_8k" msgid="3626855847189438896">"ROC 8K"</string>
+ <string name="mediasize_chinese_roc_16k" msgid="9182191577022943355">"ROC 16K"</string>
+ <string name="mediasize_chinese_prc_1" msgid="4793232644980170500">"PRC 1"</string>
+ <string name="mediasize_chinese_prc_2" msgid="5404109730975720670">"PRC 2"</string>
+ <string name="mediasize_chinese_prc_3" msgid="1335092253339363526">"PRC 3"</string>
+ <string name="mediasize_chinese_prc_4" msgid="9167997800486569834">"PRC 4"</string>
+ <string name="mediasize_chinese_prc_5" msgid="845875168823541497">"PRC 5"</string>
+ <string name="mediasize_chinese_prc_6" msgid="3220325667692648789">"PRC 6"</string>
+ <string name="mediasize_chinese_prc_7" msgid="1776792138507038527">"PRC 7"</string>
+ <string name="mediasize_chinese_prc_8" msgid="1417176642687456692">"PRC 8"</string>
+ <string name="mediasize_chinese_prc_9" msgid="4785983473123798365">"PRC 9"</string>
+ <string name="mediasize_chinese_prc_10" msgid="7847982299391851899">"PRC 10"</string>
+ <string name="mediasize_chinese_prc_16k" msgid="262793383539980677">"PRC 16K"</string>
+ <string name="mediasize_chinese_om_pa_kai" msgid="5256815579447959814">"Pa Kai"</string>
+ <string name="mediasize_chinese_om_dai_pa_kai" msgid="7336412963441354407">"Dai Pa Kai"</string>
+ <string name="mediasize_chinese_om_jurro_ku_kai" msgid="6324465444100490742">"Jurro Ku Kai"</string>
+ <string name="mediasize_japanese_jis_b10" msgid="1787262845627694376">"JIS B10"</string>
+ <string name="mediasize_japanese_jis_b9" msgid="3336035783663287470">"JIS B9"</string>
+ <string name="mediasize_japanese_jis_b8" msgid="6195398299104345731">"JIS B8"</string>
+ <string name="mediasize_japanese_jis_b7" msgid="1674621886902828884">"JIS B7"</string>
+ <string name="mediasize_japanese_jis_b6" msgid="4170576286062657435">"JIS B6"</string>
+ <string name="mediasize_japanese_jis_b5" msgid="4899297958100032533">"JIS B5"</string>
+ <string name="mediasize_japanese_jis_b4" msgid="4213158129126666847">"JIS B4"</string>
+ <string name="mediasize_japanese_jis_b3" msgid="8513715307410310696">"JIS B3"</string>
+ <string name="mediasize_japanese_jis_b2" msgid="4777690211897131190">"JIS B2"</string>
+ <string name="mediasize_japanese_jis_b1" msgid="4608142385457034603">"JIS B1"</string>
+ <string name="mediasize_japanese_jis_b0" msgid="7587108366572243991">"JIS B0"</string>
+ <string name="mediasize_japanese_jis_exec" msgid="5244075432263649068">"JIS Exec"</string>
+ <string name="mediasize_japanese_chou4" msgid="4941652015032631361">"Chou4"</string>
+ <string name="mediasize_japanese_chou3" msgid="6387319169263957010">"Chou3"</string>
+ <string name="mediasize_japanese_chou2" msgid="1299112025415343982">"Chou2"</string>
+ <string name="mediasize_japanese_hagaki" msgid="8070115620644254565">"Hagaki"</string>
+ <string name="mediasize_japanese_oufuku" msgid="6049065587307896564">"Oufuku"</string>
+ <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
+ <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
+ <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
+ <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"ଅଜଣା ପୋର୍ଟ୍ରେଟ୍"</string>
+ <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"ଅଜଣା ଲ୍ୟାଣ୍ଡସ୍କେପ୍"</string>
+ <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"କ୍ୟାନ୍ସଲ୍ କରାଗଲା"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"କଣ୍ଟେଣ୍ଟ ଲେଖିବାବେଳେ ତ୍ରୁଟି"</string>
+ <string name="reason_unknown" msgid="6048913880184628119">"ଅଜଣା"</string>
+ <string name="reason_service_unavailable" msgid="7824008732243903268">"ପ୍ରିଣ୍ଟ ସେବାକୁ ସକ୍ଷମ କରାଯାଇନାହିଁ"</string>
+ <string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> ସେବା ଇନଷ୍ଟଲ୍ କରାଯାଇସାରିଛି"</string>
+ <string name="print_service_installed_message" msgid="5897362931070459152">"ସକ୍ଷମ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for restr_pin_enter_admin_pin (8641662909467236832) -->
+ <skip />
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN ଲେଖନ୍ତୁ"</string>
+ <string name="restr_pin_incorrect" msgid="8571512003955077924">"ଭୁଲ"</string>
+ <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"ବର୍ତ୍ତମାନର PIN"</string>
+ <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"ନୂଆ PIN"</string>
+ <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"ନୂଆ PIN ନିଶ୍ଚିତ କରନ୍ତୁ"</string>
+ <string name="restr_pin_create_pin" msgid="8017600000263450337">"ପ୍ରତିବନ୍ଧକ ବଦଳାଇବା ପାଇଁ ଏକ PIN ତିଆରି କରନ୍ତୁ"</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINଗୁଡିକ ମେଳ ହେଉନାହିଁ। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ବହୁତ ଛୋଟ। ଅତି କମ୍ରେ 4 ସଂଖ୍ୟା ବିଶିଷ୍ଟ ହେବା ଦରକାର।"</string>
+ <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ସେକେଣ୍ଡରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ</item>
+ <item quantity="one">1 ସେକେଣ୍ଡରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ</item>
+ </plurals>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
+ <string name="immersive_cling_title" msgid="8394201622932303336">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ଦେଖାଯାଉଛି"</string>
+ <string name="immersive_cling_description" msgid="3482371193207536040">"ବାହାରିବା ପାଇଁ, ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ।"</string>
+ <string name="immersive_cling_positive" msgid="5016839404568297683">"ବୁଝିଲି"</string>
+ <string name="done_label" msgid="2093726099505892398">"ହୋଇଗଲା"</string>
+ <string name="hour_picker_description" msgid="6698199186859736512">"ଘଣ୍ଟା ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string>
+ <string name="minute_picker_description" msgid="8606010966873791190">"ମିନିଟ୍ସ ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string>
+ <string name="select_hours" msgid="6043079511766008245">"ଘଣ୍ଟା ଚୟନ କରନ୍ତୁ"</string>
+ <string name="select_minutes" msgid="3974345615920336087">"ମିନିଟ୍ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="select_day" msgid="7774759604701773332">"ମାସ ଓ ଦିନ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="select_year" msgid="7952052866994196170">"ବର୍ଷ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ଡିଲିଟ୍ ହୋଇଗଲା"</string>
+ <string name="managed_profile_label_badge" msgid="2355652472854327647">"କାର୍ଯ୍ୟ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2ୟ କାର୍ଯ୍ୟ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3ୟ କାର୍ଯ୍ୟ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ଅନପିନ୍ କରିବା ପୂର୍ବରୁ PIN ପଚାରନ୍ତୁ"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ଅନପିନ୍ କରିବା ପୂର୍ବରୁ ଲକ୍ ଖୋଲିବା ପାଟର୍ନ ପଚାରନ୍ତୁ"</string>
+ <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ଅନପିନ୍ କରିବା ପୂର୍ବରୁ ପାସ୍ୱର୍ଡ ପଚାରନ୍ତୁ"</string>
+ <!-- no translation found for package_installed_device_owner (6875717669960212648) -->
+ <skip />
+ <!-- no translation found for package_updated_device_owner (1847154566357862089) -->
+ <skip />
+ <!-- no translation found for package_deleted_device_owner (2307122077550236438) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (5394663545060026162) -->
+ <skip />
+ <!-- no translation found for data_saver_description (6015391409098303235) -->
+ <skip />
+ <string name="data_saver_enable_title" msgid="4674073932722787417">"ଡାଟା ସେଭର୍ ଅନ୍ କରିବେ?"</string>
+ <string name="data_saver_enable_button" msgid="7147735965247211818">"ଅନ୍ କରନ୍ତୁ"</string>
+ <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+ <item quantity="other">%1$d ମିନିଟ୍ ପାଇଁ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ <item quantity="one">ଏକ ମିନିଟ୍ ପାଇଁ (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="6830154222366042597">
+ <item quantity="other">%1$d ମିନିଟ୍ ପାଇଁ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ <item quantity="one">1 ମିନିଟ୍ ପାଇଁ (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+ <item quantity="other">%1$d ଘଣ୍ଟା ପାଇଁ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ <item quantity="one">ଏକ ଘଣ୍ଟା ପାଇଁ (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="4787552595253082371">
+ <item quantity="other">%1$d ଘଣ୍ଟା ପାଇଁ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ <item quantity="one">1 ଘଣ୍ଟା ପାଇଁ (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+ <item quantity="other">%d ମିନିଟ୍ ପାଇଁ</item>
+ <item quantity="one">ଏକ ମିନିଟ୍ ପାଇଁ</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2199350154433426128">
+ <item quantity="other">%d ମିନିଟ୍ ପାଇଁ</item>
+ <item quantity="one">1 ମିନିଟ୍ ପାଇଁ</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+ <item quantity="other">%d ଘଣ୍ଟା ପାଇଁ</item>
+ <item quantity="one">ଏକ ଘଣ୍ଟା ପାଇଁ</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_short" formatted="false" msgid="6748277774662434217">
+ <item quantity="other">%d ଘଣ୍ଟା ପାଇଁ</item>
+ <item quantity="one">1 ଘଣ୍ଟା ପାଇଁ</item>
+ </plurals>
+ <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ପରବର୍ତ୍ତୀ ଆଲାର୍ମ) ପର୍ଯ୍ୟନ୍ତ"</string>
+ <!-- no translation found for zen_mode_forever (931849471004038757) -->
+ <skip />
+ <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"ଆପଣ \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅଫ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string>
+ <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
+ <string name="toolbar_collapse_description" msgid="2821479483960330739">"ଛୋଟ କରନ୍ତୁ"</string>
+ <string name="zen_mode_feature_name" msgid="5254089399895895004">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"ବନ୍ଦ ରହିବାର ସମୟ"</string>
+ <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"ସପ୍ତାହରାତି"</string>
+ <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"ସପ୍ତାହାନ୍ତ"</string>
+ <string name="zen_mode_default_events_name" msgid="8158334939013085363">"ଇଭେଣ୍ଟ"</string>
+ <!-- no translation found for zen_mode_default_every_night_name (3012363838882944175) -->
+ <skip />
+ <string name="muted_by" msgid="6147073845094180001">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> ଦ୍ୱାରା ନିଶବ୍ଦ କରନ୍ତୁ"</string>
+ <string name="system_error_wipe_data" msgid="6608165524785354962">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ଏକ ସମସ୍ୟା ରହିଛି ଏବଂ ଆପଣ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଅସ୍ଥିର ରହିପାରେ।"</string>
+ <string name="system_error_manufacturer" msgid="8086872414744210668">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ଏକ ସମସ୍ୟା ରହିଛି। ବିବରଣୀ ପାଇଁ ଆପଣଙ୍କ ଉତ୍ପାଦକଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
+ <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD ଅନୁରୋଧ DIAL ଅନୁରୋଧକୁ ସଂଶୋଧନ କରାଗଲା।"</string>
+ <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD ଅନୁରୋଧ SS ଅନୁରୋଧକୁ ସଂଶୋଧନ କରାଗଲା।"</string>
+ <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD ଅନୁରୋଧ ନୂଆ USSD ଅନୁରୋଧକୁ ସଂଶୋଧନ କରାଗଲା।"</string>
+ <!-- no translation found for stk_cc_ussd_to_dial_video (585340552561515305) -->
+ <skip />
+ <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ଅନୁରୋଧ DIAL ଅନୁରୋଧକୁ ସଂଶୋଧନ କରାଗଲା।"</string>
+ <!-- no translation found for stk_cc_ss_to_dial_video (4306210904450719045) -->
+ <skip />
+ <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ଅନୁରୋଧ USSD ଅନୁରୋଧକୁ ସଂଶୋଧନ କରାଗଲା।"</string>
+ <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ଅନୁରୋଧ ନୂତନ SS ଅନୁରୋଧକୁ ସଂଶୋଧନ କରାଗଲା।"</string>
+ <string name="notification_work_profile_content_description" msgid="4600554564103770764">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
+ <!-- no translation found for expand_button_content_description_collapsed (3609784019345534652) -->
+ <skip />
+ <!-- no translation found for expand_button_content_description_expanded (8520652707158554895) -->
+ <skip />
+ <string name="expand_action_accessibility" msgid="5307730695723718254">"ଟୋଗଲ୍ ସମ୍ପ୍ରସାରଣ"</string>
+ <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB ପେରିଫେରିଆଲ୍ ପୋର୍ଟ"</string>
+ <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+ <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB ପେରିଫେରିଆଲ୍ ପୋର୍ଟ"</string>
+ <string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"ଅଧିକ ବିକଳ୍ପ"</string>
+ <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"ଓଭରଫ୍ଲୋ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="maximize_button_text" msgid="7543285286182446254">"ବଡ଼ କରନ୍ତୁ"</string>
+ <string name="close_button_text" msgid="3937902162644062866">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
+ <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ଚୟନିତ</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ଚୟନିତ</item>
+ </plurals>
+ <!-- no translation found for default_notification_channel_label (5929663562028088222) -->
+ <skip />
+ <!-- no translation found for importance_from_user (7318955817386549931) -->
+ <skip />
+ <string name="importance_from_person" msgid="9160133597262938296">"ସମ୍ପୃକ୍ତ ଲୋକଙ୍କ କାରଣରୁ ଏହା ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଅଟେ।"</string>
+ <!-- no translation found for user_creation_account_exists (1942606193570143289) -->
+ <skip />
+ <!-- no translation found for user_creation_adding (4482658054622099197) -->
+ <skip />
+ <!-- no translation found for language_selection_title (2680677278159281088) -->
+ <skip />
+ <string name="country_selection_title" msgid="2954859441620215513">"ପସନ୍ଦର ଅଞ୍ଚଳ"</string>
+ <string name="search_language_hint" msgid="7042102592055108574">"ଭାଷାର ନାମ ଟାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="language_picker_section_suggested" msgid="8414489646861640885">"ପରାମର୍ଶିତ"</string>
+ <string name="language_picker_section_all" msgid="3097279199511617537">"ସମସ୍ତ ଭାଷା"</string>
+ <string name="region_picker_section_all" msgid="8966316787153001779">"ସମସ୍ତ ଅଞ୍ଚଳ"</string>
+ <string name="locale_search_menu" msgid="2560710726687249178">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+ <!-- no translation found for work_mode_off_title (1118691887588435530) -->
+ <skip />
+ <!-- no translation found for work_mode_off_message (5130856710614337649) -->
+ <skip />
+ <string name="work_mode_turn_on" msgid="2062544985670564875">"ଅନ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
+ <skip />
+ <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
+ <skip />
+ <string name="new_sms_notification_title" msgid="8442817549127555977">"ଆପଣଙ୍କ ପାଖରେ ନୂଆ ମେସେଜ୍ ରହିଛି"</string>
+ <string name="new_sms_notification_content" msgid="7002938807812083463">"ଦେଖିବା ପାଇଁ SMS ଆପ୍ ଖୋଲନ୍ତୁ"</string>
+ <!-- no translation found for user_encrypted_title (9054897468831672082) -->
+ <skip />
+ <!-- no translation found for user_encrypted_message (4923292604515744267) -->
+ <skip />
+ <!-- no translation found for user_encrypted_detail (5708447464349420392) -->
+ <skip />
+ <!-- no translation found for profile_encrypted_detail (3700965619978314974) -->
+ <skip />
+ <!-- no translation found for profile_encrypted_message (6964994232310195874) -->
+ <skip />
+ <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) -->
+ <skip />
+ <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) -->
+ <skip />
+ <string name="pin_target" msgid="3052256031352291362">"ପିନ୍"</string>
+ <!-- no translation found for unpin_target (3556545602439143442) -->
+ <skip />
+ <string name="app_info" msgid="6856026610594615344">"ଆପ୍ ସୂଚନା"</string>
+ <!-- no translation found for negative_duration (5688706061127375131) -->
+ <skip />
+ <string name="demo_starting_message" msgid="5268556852031489931">"ଡେମୋ ଆରମ୍ଭ କରାଯାଉଛି…"</string>
+ <string name="demo_restarting_message" msgid="952118052531642451">"ଡିଭାଇସ୍କୁ ରିସେଟ୍ କରାଯାଉଛି…"</string>
+ <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ଅକ୍ଷମ ହୋଇଛି <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <string name="conference_call" msgid="3751093130790472426">"କନ୍ଫରେନ୍ସ କଲ୍"</string>
+ <string name="tooltip_popup_title" msgid="5253721848739260181">"ଟୁଲଟିପ୍"</string>
+ <!-- no translation found for app_category_game (5431836943981492993) -->
+ <skip />
+ <!-- no translation found for app_category_audio (1659853108734301647) -->
+ <skip />
+ <!-- no translation found for app_category_video (2728726078629384196) -->
+ <skip />
+ <!-- no translation found for app_category_image (4867854544519846048) -->
+ <skip />
+ <!-- no translation found for app_category_social (5842783057834965912) -->
+ <skip />
+ <!-- no translation found for app_category_news (7496506240743986873) -->
+ <skip />
+ <!-- no translation found for app_category_maps (5878491404538024367) -->
+ <skip />
+ <!-- no translation found for app_category_productivity (3742083261781538852) -->
+ <skip />
+ <!-- no translation found for device_storage_monitor_notification_channel (3295871267414816228) -->
+ <skip />
+ <!-- no translation found for adb_debugging_notification_channel_tv (5537766997350092316) -->
+ <skip />
+ <!-- no translation found for time_picker_hour_label (2979075098868106450) -->
+ <skip />
+ <!-- no translation found for time_picker_minute_label (5168864173796598399) -->
+ <skip />
+ <!-- no translation found for time_picker_header_text (143536825321922567) -->
+ <skip />
+ <!-- no translation found for time_picker_input_error (7574999942502513765) -->
+ <skip />
+ <!-- no translation found for time_picker_prompt_label (7588093983899966783) -->
+ <skip />
+ <!-- no translation found for time_picker_text_input_mode_description (4148166758173708199) -->
+ <skip />
+ <!-- no translation found for time_picker_radial_mode_description (4953403779779557198) -->
+ <skip />
+ <!-- no translation found for autofill_picker_accessibility_title (8469043291648711535) -->
+ <skip />
+ <!-- no translation found for autofill_save_accessibility_title (7244365268417107822) -->
+ <skip />
+ <!-- no translation found for autofill_error_cannot_autofill (7402758580060110371) -->
+ <skip />
+ <!-- no translation found for autofill_picker_no_suggestions (3908514303773350735) -->
+ <skip />
+ <!-- no translation found for autofill_picker_some_suggestions (5506565809835815274) -->
+ <!-- no translation found for autofill_save_title (3345527308992082601) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_type (8637809388029313305) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_2types (5214035651838265325) -->
+ <skip />
+ <!-- no translation found for autofill_save_title_with_3types (6943161834231458441) -->
+ <skip />
+ <!-- no translation found for autofill_save_yes (6398026094049005921) -->
+ <skip />
+ <!-- no translation found for autofill_save_no (2625132258725581787) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_password (5288448918465971568) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_address (4936707762193009542) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_credit_card (7127694776265563071) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_username (239040540379769562) -->
+ <skip />
+ <!-- no translation found for autofill_save_type_email_address (5752949432129262174) -->
+ <skip />
+ <!-- no translation found for etws_primary_default_message_earthquake (5541962250262769193) -->
+ <skip />
+ <!-- no translation found for etws_primary_default_message_tsunami (1887685943498368548) -->
+ <skip />
+ <!-- no translation found for etws_primary_default_message_earthquake_and_tsunami (998797956848445862) -->
+ <skip />
+ <!-- no translation found for etws_primary_default_message_test (2709597093560037455) -->
+ <skip />
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
+ <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
+ <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
+ <skip />
+ <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
+ <skip />
+ <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
+ <skip />
+ <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
+ <skip />
+ <!-- no translation found for popup_window_default_title (4874318849712115433) -->
+ <skip />
+ <!-- no translation found for slice_more_content (8504342889413274608) -->
+ <skip />
+ <!-- no translation found for shortcut_restored_on_lower_version (4860853725206702336) -->
+ <skip />
+ <!-- no translation found for shortcut_restore_not_supported (5028808567940014190) -->
+ <skip />
+ <!-- no translation found for shortcut_restore_signature_mismatch (2406209324521327518) -->
+ <skip />
+ <!-- no translation found for shortcut_restore_unknown_issue (8703738064603262597) -->
+ <skip />
+ <!-- no translation found for shortcut_disabled_reason_unknown (5276016910284687075) -->
+ <skip />
+ <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
+ <skip />
+ <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
+ <skip />
+ <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
+ <skip />
+ <!-- no translation found for slices_permission_request (8484943441501672932) -->
+ <skip />
+ <!-- no translation found for screenshot_edit (7867478911006447565) -->
+ <skip />
+ <!-- no translation found for notification_channel_system_changes (5072715579030948646) -->
+ <skip />
+ <!-- no translation found for zen_upgrade_notification_title (3799603322910377294) -->
+ <skip />
+ <!-- no translation found for zen_upgrade_notification_content (6603123479476554768) -->
+ <skip />
+</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 45512a5..5ab8d33 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -181,7 +181,7 @@
<string name="network_logging_notification_title" msgid="6399790108123704477">"O dispositivo é gerenciado"</string>
<string name="network_logging_notification_text" msgid="7930089249949354026">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string>
<string name="factory_reset_warning" msgid="5423253125642394387">"Seu dispositivo será limpo"</string>
- <string name="factory_reset_message" msgid="7972496262232832457">"Não é possível usar o app para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string>
+ <string name="factory_reset_message" msgid="9024647691106150160">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string>
<string name="printing_disabled_by" msgid="8936832919072486965">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opções do tablet"</string>
@@ -236,6 +236,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
+ <string name="global_action_toggle_battery_saver" msgid="708515500418994208">"Economia de bateria"</string>
+ <string name="global_action_battery_saver_on_status" msgid="484059130698197787">"A Economia de bateria está DESATIVADA"</string>
+ <string name="global_action_battery_saver_off_status" msgid="75550964969478405">"A Economia de bateria está ATIVADA"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Configurações"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Assistência"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
@@ -305,7 +308,7 @@
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestos de impressão digital"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Pode captar gestos realizados no sensor de impressão digital do dispositivo."</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Pode captar gestos realizados no sensor de impressão digital do dispositivo."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -356,6 +359,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite que o app torne partes de si mesmo persistentes na memória. Pode limitar a memória disponível para outros apps, deixando o tablet mais lento."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permite que o app torne partes de si mesmo persistentes na memória. Isso pode limitar a memória disponível para outros apps, deixando a TV mais lenta."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite que o app torne partes de si mesmo persistentes na memória. Pode limitar a memória disponível para outros apps, deixando o telefone mais lento."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"executar serviço em primeiro plano"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Permite que o app use serviços em primeiro plano."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"medir o espaço de armazenamento do app"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite que o app recupere o código, os dados e os tamanhos de cache"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"modificar configurações do sistema"</string>
@@ -802,6 +807,8 @@
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio com padrão."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio facial."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio com PIN."</string>
+ <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Desbloqueio com PIN do SIM."</string>
+ <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Desbloqueio com PUK do SIM."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio com senha."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área do padrão."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string>
@@ -1074,29 +1081,33 @@
<string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"Verificar atualizações"</string>
<string name="smv_application" msgid="3307209192155442829">"O app <xliff:g id="APPLICATION">%1$s</xliff:g>, processo <xliff:g id="PROCESS">%2$s</xliff:g>, violou a política StrictMode imposta automaticamente."</string>
<string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string>
- <string name="android_upgrading_title" msgid="1584192285441405746">"O Android está sendo atualizado..."</string>
- <string name="android_start_title" msgid="8418054686415318207">"O Android está iniciando..."</string>
+ <!-- no translation found for android_upgrading_title (7513829952443484438) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (4503169817302593560) -->
+ <skip />
+ <!-- no translation found for android_upgrading_title (7009520271220804517) -->
+ <skip />
+ <!-- no translation found for android_start_title (4536778526365907780) -->
+ <skip />
+ <!-- no translation found for android_start_title (4929837533850340472) -->
+ <skip />
+ <!-- no translation found for android_start_title (7467484093260449437) -->
+ <skip />
<string name="android_upgrading_fstrim" msgid="8036718871534640010">"Otimizando o armazenamento."</string>
- <string name="android_upgrading_notification_title" msgid="8428357096969413169">"Concluindo atualização do Android…"</string>
- <string name="android_upgrading_notification_body" msgid="5761201379457064286">"Alguns apps podem não funcionar corretamente até que a atualização seja concluída"</string>
+ <!-- no translation found for android_upgrading_notification_title (1511552415039349062) -->
+ <skip />
<string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> está fazendo upgrade…"</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"Otimizando app <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
<string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Concluindo a inicialização."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
- <!-- no translation found for heavy_weight_notification_detail (2304833848484424985) -->
- <skip />
- <!-- no translation found for heavy_weight_switcher_title (387882830435195342) -->
- <skip />
- <!-- no translation found for heavy_weight_switcher_text (4176781660362912010) -->
- <skip />
- <!-- no translation found for old_app_action (3044685170829526403) -->
- <skip />
- <!-- no translation found for new_app_action (6694851182870774403) -->
- <skip />
- <!-- no translation found for new_app_description (5894852887817332322) -->
- <skip />
+ <string name="heavy_weight_notification_detail" msgid="2304833848484424985">"Toque para voltar ao jogo"</string>
+ <string name="heavy_weight_switcher_title" msgid="387882830435195342">"Escolha o jogo"</string>
+ <string name="heavy_weight_switcher_text" msgid="4176781660362912010">"Para ter um melhor desempenho, apenas um desses jogos pode ser aberto por vez."</string>
+ <string name="old_app_action" msgid="3044685170829526403">"Voltar para o app <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_action" msgid="6694851182870774403">"Abrir <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_description" msgid="5894852887817332322">"O app <xliff:g id="OLD_APP">%1$s</xliff:g> será fechado sem salvar"</string>
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> excedeu o limite de memória"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"O despejo de heap foi coletado. Toque para compartilhar"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"Compartilhar despejo de heap?"</string>
@@ -1138,7 +1149,8 @@
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Não foi possível conectar-se à rede Wi‑Fi"</string>
<string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toque para ver todas as redes"</string>
<string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectar"</string>
- <string name="wifi_available_action_all_networks" msgid="1100098935861622985">"Todas as redes"</string>
+ <!-- no translation found for wifi_available_action_all_networks (4368435796357931006) -->
+ <skip />
<string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"O Wi‑Fi será ativado automaticamente"</string>
<string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Quando você estiver perto de uma rede salva de alta qualidade"</string>
<string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Não ativar novamente"</string>
@@ -1204,6 +1216,7 @@
<string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Ativar serviço móvel"</string>
<string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Faça o download do app da operadora para ativar seu novo SIM"</string>
+ <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo SIM"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Fazer download do app"</string>
<string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo SIM inserido"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Toque para configurar"</string>
@@ -1247,7 +1260,7 @@
<string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> exibido sobre outros apps"</string>
<string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> exibido sobre outros apps."</string>
<string name="alert_windows_notification_message" msgid="8917232109522912560">"Se você não deseja que o <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
- <string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"DESATIVAR"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="2902891971380544651">"Desativar"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string>
@@ -1418,22 +1431,19 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
- <string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
- <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
- <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
+ <string name="data_usage_warning_title" msgid="6499834033204801605">"Aviso de dados"</string>
+ <string name="data_usage_warning_body" msgid="7340198905103751676">"Você usou <xliff:g id="APP">%s</xliff:g> de dados"</string>
<string name="data_usage_mobile_limit_title" msgid="6561099244084267376">"Limite de dados móveis atingido"</string>
<string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Limite de dados Wi-Fi atingido"</string>
- <string name="data_usage_limit_body" msgid="291731708279614081">"Dados pausados no resto do ciclo"</string>
- <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Limite de dados 2G-3G excedido"</string>
- <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Limite de dados 4G excedido"</string>
- <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Limite de dados do celular excedido"</string>
- <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Limite de dados Wi-Fi excedido"</string>
- <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> acima do limite especificado."</string>
+ <string name="data_usage_limit_body" msgid="2908179506560812973">"Uso de dados pausado pelo restante do seu ciclo"</string>
+ <string name="data_usage_mobile_limit_snoozed_title" msgid="3171402244827034372">"Acima do limite de dados móveis"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="3547771791046344188">"Acima do limite de dados Wi-Fi"</string>
+ <string name="data_usage_limit_snoozed_body" msgid="1671222777207603301">"Você ultrapassou <xliff:g id="SIZE">%s</xliff:g> do limite definido"</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Dados de segundo plano restritos"</string>
<string name="data_usage_restricted_body" msgid="469866376337242726">"Toque para remover a restrição."</string>
- <string name="data_usage_rapid_title" msgid="4579994056245665351">"Uso de dados excessivo"</string>
- <string name="data_usage_rapid_body" msgid="4899922842674185567">"Seu uso de dados nos últimos dias é maior que o normal. Toque para ver o uso e as configurações."</string>
+ <string name="data_usage_rapid_title" msgid="1809795402975261331">"Alto uso de dados móveis"</string>
+ <string name="data_usage_rapid_body" msgid="6897825788682442715">"Seus apps usaram mais dados do que o normal"</string>
+ <string name="data_usage_rapid_app_body" msgid="5396680996784142544">"O app <xliff:g id="APP">%s</xliff:g> usou mais dados do que o normal"</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Certificado de segurança"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Este certificado é válido."</string>
<string name="issued_to" msgid="454239480274921032">"Emitido para:"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 796030e..6d23fab 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1114,6 +1114,9 @@
<!-- The color applied to framework switch thumbs in their normal state. -->
<attr name="colorSwitchThumbNormal" format="color" />
+ <!-- The color applied to framework progress and seek bar backgrounds in their normal state. -->
+ <attr name="colorProgressBackgroundNormal" format="color" />
+
<!-- The color applied to the edge effect on scrolling containers. -->
<attr name="colorEdgeEffect" format="color" />
@@ -7975,9 +7978,7 @@
android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
-->
<attr name="maxLongVersionCode" format="string" />
- <!-- The resource id of view that contains the URL bar of the HTML page being loaded.
- Typically used when compatibility mode is used in a browser.
- -->
+ <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
<attr name="urlBarResourceId" format="string" />
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fa9cab5..cf13d1c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2396,6 +2396,7 @@
<!-- depends on ImportanceExtractor-->
<item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
<item>com.android.server.notification.VisibilityExtractor</item>
+ <!-- Depends on ZenModeExtractor -->
<item>com.android.server.notification.BadgeExtractor</item>
</string-array>
@@ -2513,9 +2514,8 @@
<item>restart</item>
<item>lockdown</item>
<item>logout</item>
- <item>screenshot</item>
<item>bugreport</item>
- <item>users</item>
+ <item>screenshot</item>
</string-array>
<!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7d5d1ba..2c0deed 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,6 +2869,7 @@
<public name="outlineSpotShadowColor" />
<public name="outlineAmbientShadowColor" />
<public name="maxLongVersionCode" />
+ <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
<public name="urlBarResourceId" />
<!-- @hide @SystemApi -->
<public name="userRestriction" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 15dffc0..a5bd179 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4883,7 +4883,7 @@
<!-- Title for the notification channel notifying user of settings system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
<string name="notification_channel_system_changes">System changes</string>
<!-- Title of notification indicating do not disturb settings have changed when upgrading to P -->
- <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string>
+ <string name="zen_upgrade_notification_title">Do Not Disturb is hiding notifications to help you focus</string>
<!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
- <string name="zen_upgrade_notification_content">Tap to check your behavior settings for interruptions</string>
+ <string name="zen_upgrade_notification_content">This is a new feature from the latest system update. Tap to change.</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 979a0d6..97116f5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1421,6 +1421,7 @@
<java-symbol type="layout" name="action_menu_layout" />
<java-symbol type="layout" name="action_mode_close_item" />
<java-symbol type="layout" name="alert_dialog" />
+ <java-symbol type="layout" name="cascading_menu_item_layout" />
<java-symbol type="layout" name="choose_account" />
<java-symbol type="layout" name="choose_account_row" />
<java-symbol type="layout" name="choose_account_type" />
@@ -2457,6 +2458,7 @@
<java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" />
<java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" />
<java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" />
+ <java-symbol type="attr" name="colorProgressBackgroundNormal" />
<java-symbol type="layout" name="simple_account_item" />
<java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index cb11d8d..fdbcd8a 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -127,6 +127,7 @@
<item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="seekBarStyle">@style/Widget.DeviceDefault.SeekBar</item>
<item name="ratingBarStyle">@style/Widget.DeviceDefault.RatingBar</item>
<item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.RatingBar.Indicator</item>
@@ -230,6 +231,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -253,6 +255,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -278,6 +281,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -302,6 +306,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -334,6 +339,7 @@
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -357,6 +363,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -379,6 +386,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -402,6 +410,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -441,6 +450,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -465,6 +475,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -487,6 +498,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -511,6 +523,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -534,6 +547,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -557,6 +571,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -580,6 +595,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -603,6 +619,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -626,6 +643,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -647,6 +665,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -668,6 +687,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -748,6 +768,7 @@
<item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="seekBarStyle">@style/Widget.DeviceDefault.Light.SeekBar</item>
<item name="ratingBarStyle">@style/Widget.DeviceDefault.Light.RatingBar</item>
<item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
@@ -846,6 +867,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -868,6 +890,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -891,6 +914,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -916,6 +940,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -940,6 +965,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -970,6 +996,7 @@
<item name="colorAccent">@color/accent_device_default_light</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -993,6 +1020,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1015,6 +1043,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1038,6 +1067,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1087,6 +1117,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1111,6 +1142,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1133,6 +1165,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1157,6 +1190,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1180,6 +1214,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1201,6 +1236,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1222,6 +1258,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1256,6 +1293,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1278,6 +1316,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1290,6 +1329,7 @@
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1313,6 +1353,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1335,6 +1376,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1357,6 +1399,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1379,6 +1422,7 @@
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
@@ -1408,6 +1452,7 @@
<item name="colorAccent">@color/accent_device_default_light</item>
<!-- Progress bar attributes -->
+ <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
<item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
</style>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 76d9ea6..9b633fc 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -403,6 +403,7 @@
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/btn_default_material_dark</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
+ <item name="colorProgressBackgroundNormal">?attr/colorControlNormal</item>
<!-- Tooltip popup properties -->
<item name="tooltipForegroundColor">@color/foreground_material_light</item>
@@ -777,6 +778,7 @@
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
+ <item name="colorProgressBackgroundNormal">?attr/colorControlNormal</item>
<!-- Tooltip popup properties -->
<item name="tooltipForegroundColor">@color/foreground_material_dark</item>
@@ -837,6 +839,7 @@
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
+ <item name="colorProgressBackgroundNormal">?attr/colorControlNormal</item>
</style>
<!-- Theme overlay that replaces colors with their dark versions but preserves
@@ -870,6 +873,7 @@
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/btn_default_material_dark</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
+ <item name="colorProgressBackgroundNormal">?attr/colorControlNormal</item>
</style>
<!-- Theme overlay that replaces the normal control color, which by default is the same as the
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 5e463d8..2d3cd1c 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,9 @@
-->
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="4">
+<zen version="5">
<allow alarms="true" media="true" system="false" calls="false" messages="false" reminders="false"
events="false" />
+ <!-- all visual effects that exist as of P -->
+ <disallow suppressedVisualEffect="511" />
</zen>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index eff7c55..899d630 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -27,7 +27,6 @@
are totally dependent on the platform and can vary
significantly, so should be measured on the shipping platform
with a power meter. -->
- <item name="none">0</item>
<item name="ambient.on">0.1</item> <!-- ~100mA -->
<item name="screen.on">0.1</item> <!-- ~100mA -->
<item name="screen.full">0.1</item> <!-- ~100mA -->
diff --git a/core/res/res/xml/power_profile_test.xml b/core/res/res/xml/power_profile_test.xml
index 6dc5c7e..001cc68 100644
--- a/core/res/res/xml/power_profile_test.xml
+++ b/core/res/res/xml/power_profile_test.xml
@@ -24,9 +24,6 @@
sample values, not meant to reflect any real device.
-->
- <!-- Nothing -->
- <item name="none">0</item>
-
<!-- This is the battery capacity in mAh -->
<item name="battery.capacity">3000</item>
diff --git a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
index b28a4b5..781e343 100644
--- a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
@@ -1,15 +1,11 @@
package android.graphics.drawable;
-import static org.junit.Assert.assertTrue;
-
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Outline;
-import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Rect;
@@ -19,10 +15,12 @@
import android.test.AndroidTestCase;
import android.util.Log;
import android.util.PathParser;
+
+import org.junit.Test;
+
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
-import org.junit.Test;
@LargeTest
public class AdaptiveIconDrawableTest extends AndroidTestCase {
@@ -173,6 +171,28 @@
assertTrue("outline path should be convex", outline.mPath.isConvex());
}
+ @Test
+ public void testSetAlpha() throws Exception {
+ mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
+ mIconDrawable.setBounds(0, 0, 100, 100);
+
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+
+ mIconDrawable.draw(canvas);
+ assertEquals(255, Color.alpha(bitmap.getPixel(50, 50)));
+
+ mIconDrawable.setAlpha(200);
+ bitmap.eraseColor(Color.TRANSPARENT);
+ mIconDrawable.draw(canvas);
+ assertEquals(200, Color.alpha(bitmap.getPixel(50, 50)));
+
+ mIconDrawable.setAlpha(100);
+ bitmap.eraseColor(Color.TRANSPARENT);
+ mIconDrawable.draw(canvas);
+ assertEquals(100, Color.alpha(bitmap.getPixel(50, 50)));
+ }
+
//
// Utils
//
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6c72ac1..22a261e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -263,6 +263,7 @@
Settings.Global.LOW_BATTERY_SOUND,
Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
Settings.Global.LOW_POWER_MODE,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
Settings.Global.LTE_SERVICE_FORCED,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
Settings.Global.MDC_INITIAL_MAX_RETRY,
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index b135025..8db1bfa 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -16,8 +16,13 @@
package android.view.accessibility;
+import static org.hamcrest.Matchers.emptyCollectionOf;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
+import android.os.Parcel;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
@@ -38,10 +43,10 @@
public void testStandardActions_serializationFlagIsValid() {
AccessibilityAction brokenStandardAction = CollectionUtils.find(
new ArrayList<>(AccessibilityAction.sStandardActions),
- action -> Integer.bitCount(action.mSerializationFlag) != 1);
+ action -> Long.bitCount(action.mSerializationFlag) != 1);
if (brokenStandardAction != null) {
String message = "Invalid serialization flag(0x"
- + Integer.toHexString(brokenStandardAction.mSerializationFlag)
+ + Long.toHexString(brokenStandardAction.mSerializationFlag)
+ ") in " + brokenStandardAction;
if (brokenStandardAction.mSerializationFlag == 0L) {
message += "\nThis is likely due to an overflow";
@@ -56,7 +61,7 @@
&& action.getId() != action.mSerializationFlag);
if (brokenStandardAction != null) {
fail("Serialization flag(0x"
- + Integer.toHexString(brokenStandardAction.mSerializationFlag)
+ + Long.toHexString(brokenStandardAction.mSerializationFlag)
+ ") is different from legacy action id(0x"
+ Integer.toHexString(brokenStandardAction.getId())
+ ") in " + brokenStandardAction);
@@ -77,4 +82,36 @@
}
}
+ @Test
+ public void testStandardActions_allComeThroughParceling() {
+ for (AccessibilityAction action : AccessibilityAction.sStandardActions) {
+ final AccessibilityNodeInfo nodeWithAction = AccessibilityNodeInfo.obtain();
+ nodeWithAction.addAction(action);
+ assertThat(nodeWithAction.getActionList(), hasItem(action));
+ final Parcel parcel = Parcel.obtain();
+ nodeWithAction.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final AccessibilityNodeInfo unparceledNode =
+ AccessibilityNodeInfo.CREATOR.createFromParcel(parcel);
+ assertThat(unparceledNode.getActionList(), hasItem(action));
+ }
+ }
+
+ @Test
+ public void testEmptyListOfActions_parcelsCorrectly() {
+ // Also set text, as if there's nothing else in the parcel it can unparcel even with
+ // a bug present.
+ final String text = "text";
+ final AccessibilityNodeInfo nodeWithEmptyActionList = AccessibilityNodeInfo.obtain();
+ nodeWithEmptyActionList.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
+ nodeWithEmptyActionList.removeAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
+ nodeWithEmptyActionList.setText(text);
+ final Parcel parcel = Parcel.obtain();
+ nodeWithEmptyActionList.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final AccessibilityNodeInfo unparceledNode =
+ AccessibilityNodeInfo.CREATOR.createFromParcel(parcel);
+ assertThat(unparceledNode.getActionList(), emptyCollectionOf(AccessibilityAction.class));
+ assertThat(unparceledNode.getText(), equalTo(text));
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
index b920ca3..8e4f02c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
@@ -26,6 +26,7 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
+import android.view.textclassifier.GenerateLinksLogger;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
index 9fa9be9..6129b5b 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
@@ -16,12 +16,10 @@
package android.widget.layout.linear;
-import junit.framework.Assert;
-
-import android.widget.EditText;
import android.content.Context;
-import android.util.AttributeSet;
import android.text.BoringLayout;
+import android.util.AttributeSet;
+import android.widget.EditText;
/**
@@ -50,10 +48,8 @@
}
@Override
- protected void makeNewLayout(int w, int hintWidth,
- BoringLayout.Metrics boring,
- BoringLayout.Metrics hintMetrics,
- int ellipsizedWidth, boolean bringIntoView) {
+ public void makeNewLayout(int w, int hintWidth, BoringLayout.Metrics boring,
+ BoringLayout.Metrics hintMetrics, int ellipsizedWidth, boolean bringIntoView) {
if (w < 0) {
mFailed = true;
w = 100;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
index 312af16..06f51c9 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
@@ -104,6 +104,30 @@
}
@Test
+ public void testReadAbsolute() throws Exception {
+ final int cores = 8;
+ final int[] uids = {1, 22, 333, 4444, 5555};
+
+ final long[][] times = increaseTime(new long[uids.length][cores]);
+ when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
+ mReader.readAbsolute(mCallback);
+ for (int i = 0; i < uids.length; i++) {
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that a second call still returns absolute values
+ Mockito.reset(mCallback);
+ final long[][] times1 = increaseTime(times);
+ when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1));
+ mReader.readAbsolute(mCallback);
+ for (int i = 0; i < uids.length; i++) {
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times1[i]));
+ }
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ @Test
public void testReadDelta_malformedData() throws Exception {
final int cores = 8;
final int[] uids = {1, 22, 333, 4444, 5555};
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
index d21f541..85dce02 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
@@ -114,6 +114,34 @@
}
@Test
+ public void testReadAbsolute() throws Exception {
+ VerifiableCallback cb = new VerifiableCallback();
+ final int cores = 6;
+ final int[] clusters = {2, 4};
+ final int[] uids = {1, 22, 333, 4444, 5555};
+
+ // Verify return absolute value
+ final long[][] times = increaseTime(new long[uids.length][cores]);
+ when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times));
+ mReader.readAbsolute(cb);
+ for (int i = 0; i < uids.length; i++) {
+ cb.verify(uids[i], getTotal(clusters, times[i]));
+ }
+ cb.verifyNoMoreInteractions();
+
+ // Verify that a second call should return the same absolute value
+ cb.clear();
+ Mockito.reset(mProcReader);
+ final long[][] times1 = increaseTime(times);
+ when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times1));
+ mReader.readAbsolute(cb);
+ for (int i = 0; i < uids.length; i++) {
+ cb.verify(uids[i], getTotal(clusters, times1[i]));
+ }
+ cb.verifyNoMoreInteractions();
+ }
+
+ @Test
public void testReadDelta_malformedData() throws Exception {
final int cores = 6;
final int[] clusters = {2, 4};
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
index 0950721..a6b99c3 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
@@ -297,6 +297,46 @@
}
@Test
+ public void testReadAbsolute() throws Exception {
+ VerifiableCallback cb = new VerifiableCallback();
+ final long[] freqs = {110, 123, 145, 167, 289, 997};
+ final int[] uids = {1, 22, 333, 444, 555};
+ final long[][] times = new long[uids.length][freqs.length];
+ for (int i = 0; i < uids.length; ++i) {
+ for (int j = 0; j < freqs.length; ++j) {
+ times[i][j] = uids[i] * freqs[j] * 10;
+ }
+ }
+ when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
+ long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);
+
+ assertArrayEquals(freqs, actualFreqs);
+ // Verify that the absolute values are returned
+ when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
+ mKernelUidCpuFreqTimeReader.readAbsolute(cb);
+ for (int i = 0; i < uids.length; ++i) {
+ cb.verify(uids[i], times[i]);
+ }
+ cb.verifyNoMoreInteractions();
+
+ // Verify that a second call should still return absolute values
+ cb.clear();
+ Mockito.reset(mProcReader);
+ final long[][] newTimes1 = new long[uids.length][freqs.length];
+ for (int i = 0; i < uids.length; ++i) {
+ for (int j = 0; j < freqs.length; ++j) {
+ newTimes1[i][j] = times[i][j] + (uids[i] + freqs[j]) * 50;
+ }
+ }
+ when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1));
+ mKernelUidCpuFreqTimeReader.readAbsolute(cb);
+ for (int i = 0; i < uids.length; ++i) {
+ cb.verify(uids[i], newTimes1[i]);
+ }
+ cb.verifyNoMoreInteractions();
+ }
+
+ @Test
public void testReadDelta_malformedData() throws Exception {
final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
final int[] uids = {1, 22, 333, 4444, 5555};
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index 1d46d42..fd1027c 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -67,6 +67,7 @@
<hidden-api-whitelisted-app package="com.android.pacprocessor" />
<hidden-api-whitelisted-app package="com.android.phone" />
<hidden-api-whitelisted-app package="com.android.pmc" />
+ <hidden-api-whitelisted-app package="com.android.printspooler" />
<hidden-api-whitelisted-app package="com.android.providers.blockednumber" />
<hidden-api-whitelisted-app package="com.android.providers.contacts" />
<hidden-api-whitelisted-app package="com.android.providers.downloads" />
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index e7cfcfd..c69eb32 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -24,6 +24,8 @@
import dalvik.annotation.optimization.CriticalNative;
+import libcore.util.NativeAllocationRegistry;
+
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -38,6 +40,14 @@
private static String TAG = "FontFamily";
+ private static final NativeAllocationRegistry sBuilderRegistry = new NativeAllocationRegistry(
+ FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc(), 64);
+
+ private @Nullable Runnable mNativeBuilderCleaner;
+
+ private static final NativeAllocationRegistry sFamilyRegistry = new NativeAllocationRegistry(
+ FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc(), 64);
+
/**
* @hide
*/
@@ -48,6 +58,7 @@
public FontFamily() {
mBuilderPtr = nInitBuilder(null, 0);
+ mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr);
}
public FontFamily(@Nullable String[] langs, int variant) {
@@ -60,6 +71,7 @@
langsString = TextUtils.join(",", langs);
}
mBuilderPtr = nInitBuilder(langsString, variant);
+ mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr);
}
/**
@@ -73,7 +85,11 @@
throw new IllegalStateException("This FontFamily is already frozen");
}
mNativePtr = nCreateFamily(mBuilderPtr);
+ mNativeBuilderCleaner.run();
mBuilderPtr = 0;
+ if (mNativePtr != 0) {
+ sFamilyRegistry.registerNativeAllocation(this, mNativePtr);
+ }
return mNativePtr != 0;
}
@@ -81,24 +97,10 @@
if (mBuilderPtr == 0) {
throw new IllegalStateException("This FontFamily is already frozen or abandoned");
}
- nAbort(mBuilderPtr);
+ mNativeBuilderCleaner.run();
mBuilderPtr = 0;
}
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mNativePtr != 0) {
- nUnrefFamily(mNativePtr);
- }
- if (mBuilderPtr != 0) {
- nAbort(mBuilderPtr);
- }
- } finally {
- super.finalize();
- }
- }
-
public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight,
int italic) {
if (mBuilderPtr == 0) {
@@ -171,10 +173,10 @@
private static native long nCreateFamily(long mBuilderPtr);
@CriticalNative
- private static native void nAbort(long mBuilderPtr);
+ private static native long nGetBuilderReleaseFunc();
@CriticalNative
- private static native void nUnrefFamily(long nativePtr);
+ private static native long nGetFamilyReleaseFunc();
// By passing -1 to weigth argument, the weight value is resolved by OS/2 table in the font.
// By passing -1 to italic argument, the italic value is resolved by OS/2 table in the font.
private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex,
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 5602a3e..88701fa 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -493,7 +493,7 @@
private boolean mRequireUnpremultiplied = false;
private boolean mMutable = false;
private boolean mConserveMemory = false;
- private boolean mAsAlphaMask = false;
+ private boolean mDecodeAsAlphaMask = false;
private Rect mCropRect;
private Rect mOutPaddingRect;
private Source mSource;
@@ -730,7 +730,7 @@
* Will typically result in a {@link Bitmap.Config#HARDWARE}
* allocation, but may be software for small images. In addition, this will
* switch to software when HARDWARE is incompatible, e.g.
- * {@link #setMutable}, {@link #setAsAlphaMask}.
+ * {@link #setMutable}, {@link #setDecodeAsAlphaMask}.
*/
public static final int ALLOCATOR_DEFAULT = 0;
@@ -753,7 +753,7 @@
* Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
*
* When this is combined with incompatible options, like
- * {@link #setMutable} or {@link #setAsAlphaMask}, {@link #decodeDrawable}
+ * {@link #setMutable} or {@link #setDecodeAsAlphaMask}, {@link #decodeDrawable}
* / {@link #decodeBitmap} will throw an
* {@link java.lang.IllegalStateException}.
*/
@@ -783,6 +783,14 @@
}
/**
+ * Return the allocator for the pixel memory.
+ */
+ @Allocator
+ public int getAllocator() {
+ return mAllocator;
+ }
+
+ /**
* Specify whether the {@link Bitmap} should have unpremultiplied pixels.
*
* <p>By default, ImageDecoder will create a {@link Bitmap} with
@@ -803,6 +811,13 @@
}
/**
+ * Return whether the {@link Bitmap} will have unpremultiplied pixels.
+ */
+ public boolean getRequireUnpremultiplied() {
+ return mRequireUnpremultiplied;
+ }
+
+ /**
* Modify the image after decoding and scaling.
*
* <p>This allows adding effects prior to returning a {@link Drawable} or
@@ -823,6 +838,14 @@
}
/**
+ * Return the {@link PostProcessor} currently set.
+ */
+ @Nullable
+ public PostProcessor getPostProcessor() {
+ return mPostProcessor;
+ }
+
+ /**
* Set (replace) the {@link OnPartialImageListener} on this object.
*
* <p>Will be called if there is an error in the input. Without one, an
@@ -836,6 +859,14 @@
}
/**
+ * Return the {@link OnPartialImageListener} currently set.
+ */
+ @Nullable
+ public OnPartialImageListener getOnPartialImageListener() {
+ return mOnPartialImageListener;
+ }
+
+ /**
* Crop the output to {@code subset} of the (possibly) scaled image.
*
* <p>{@code subset} must be contained within the size set by
@@ -855,6 +886,14 @@
}
/**
+ * Return the cropping rectangle, if set.
+ */
+ @Nullable
+ public Rect getCrop() {
+ return mCropRect;
+ }
+
+ /**
* Set a Rect for retrieving nine patch padding.
*
* If the image is a nine patch, this Rect will be set to the padding
@@ -893,6 +932,13 @@
}
/**
+ * Return whether the {@link Bitmap} will be mutable.
+ */
+ public boolean getMutable() {
+ return mMutable;
+ }
+
+ /**
* Specify whether to potentially save RAM at the expense of quality.
*
* <p>Setting this to {@code true} may result in a {@link Bitmap} with a
@@ -912,24 +958,62 @@
}
/**
+ * Return whether this object will try to save RAM at the expense of quality.
+ *
+ * <p>This returns whether {@link #setConserveMemory} was set to {@code true}.
+ * It may still return {@code true} even if the {@code ImageDecoder} does not
+ * have a way to save RAM at the expense of quality for this image.</p>
+ */
+ public boolean getConserveMemory() {
+ return mConserveMemory;
+ }
+
+ /**
* Specify whether to potentially treat the output as an alpha mask.
*
* <p>If this is set to {@code true} and the image is encoded in a format
* with only one channel, treat that channel as alpha. Otherwise this call has
* no effect.</p>
*
- * <p>setAsAlphaMask is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
+ * <p>setDecodeAsAlphaMask is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
* combine them will result in {@link #decodeDrawable}/
* {@link #decodeBitmap} throwing an
* {@link java.lang.IllegalStateException}.</p>
*
* @return this object for chaining.
*/
- public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
- mAsAlphaMask = asAlphaMask;
+ public ImageDecoder setDecodeAsAlphaMask(boolean decodeAsAlphaMask) {
+ mDecodeAsAlphaMask = decodeAsAlphaMask;
return this;
}
+ /** @removed
+ * @deprecated Call {@link #setDecodeAsAlphaMask} instead.
+ */
+ @java.lang.Deprecated
+ public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
+ return this.setDecodeAsAlphaMask(asAlphaMask);
+ }
+
+ /**
+ * Return whether to treat single channel input as alpha.
+ *
+ * <p>This returns whether {@link #setDecodeAsAlphaMask} was set to {@code true}.
+ * It may still return {@code true} even if the image has more than one
+ * channel and therefore will not be treated as an alpha mask.</p>
+ */
+ public boolean getDecodeAsAlphaMask() {
+ return mDecodeAsAlphaMask;
+ }
+
+ /** @removed
+ * @deprecated Call {@link #getDecodeAsAlphaMask} instead.
+ */
+ @java.lang.Deprecated
+ public boolean getAsAlphaMask() {
+ return this.getDecodeAsAlphaMask();
+ }
+
@Override
public void close() {
mCloseGuard.close();
@@ -960,7 +1044,7 @@
if (mMutable) {
throw new IllegalStateException("Cannot make mutable HARDWARE Bitmap!");
}
- if (mAsAlphaMask) {
+ if (mDecodeAsAlphaMask) {
throw new IllegalStateException("Cannot make HARDWARE Alpha mask Bitmap!");
}
}
@@ -992,7 +1076,7 @@
return nDecodeBitmap(mNativePtr, partialImagePtr,
postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
- mConserveMemory, mAsAlphaMask);
+ mConserveMemory, mDecodeAsAlphaMask);
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1224,7 +1308,7 @@
int width, int height,
@Nullable Rect cropRect, boolean mutable,
int allocator, boolean requireUnpremul,
- boolean conserveMemory, boolean asAlphaMask)
+ boolean conserveMemory, boolean decodeAsAlphaMask)
throws IOException;
private static native Size nGetSampledSize(long nativePtr,
int sampleSize);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 38beebd..f27c11d 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -42,6 +42,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import dalvik.annotation.optimization.CriticalNative;
+
+import libcore.util.NativeAllocationRegistry;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@@ -71,6 +75,9 @@
private static String TAG = "Typeface";
+ private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ Typeface.class.getClassLoader(), nativeGetReleaseFunc(), 64);
+
/** The default NORMAL typeface object */
public static final Typeface DEFAULT;
/**
@@ -911,6 +918,7 @@
}
native_instance = ni;
+ sRegistry.registerNativeAllocation(this, native_instance);
mStyle = nativeGetStyle(ni);
mWeight = nativeGetWeight(ni);
}
@@ -1120,16 +1128,6 @@
}
@Override
- protected void finalize() throws Throwable {
- try {
- nativeUnref(native_instance);
- native_instance = 0; // Other finalizers can still call us.
- } finally {
- super.finalize();
- }
- }
-
- @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -1173,10 +1171,18 @@
private static native long nativeCreateFromTypefaceWithVariation(
long native_instance, List<FontVariationAxis> axes);
private static native long nativeCreateWeightAlias(long native_instance, int weight);
- private static native void nativeUnref(long native_instance);
- private static native int nativeGetStyle(long native_instance);
- private static native int nativeGetWeight(long native_instance);
private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic);
- private static native void nativeSetDefault(long native_instance);
private static native int[] nativeGetSupportedAxes(long native_instance);
+
+ @CriticalNative
+ private static native void nativeSetDefault(long nativePtr);
+
+ @CriticalNative
+ private static native int nativeGetStyle(long nativePtr);
+
+ @CriticalNative
+ private static native int nativeGetWeight(long nativePtr);
+
+ @CriticalNative
+ private static native long nativeGetReleaseFunc();
}
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 1d0cfa5..fdd638a 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -44,6 +44,7 @@
import android.util.PathParser;
import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -668,13 +669,7 @@
@Override
public void setAlpha(int alpha) {
- final ChildDrawable[] array = mLayerState.mChildren;
- for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
- final Drawable dr = array[i].mDrawable;
- if (dr != null) {
- dr.setAlpha(alpha);
- }
- }
+ mPaint.setAlpha(alpha);
}
@Override
diff --git a/libs/incident/proto/android/section.proto b/libs/incident/proto/android/section.proto
index ef6a8ff..b3ed393 100644
--- a/libs/incident/proto/android/section.proto
+++ b/libs/incident/proto/android/section.proto
@@ -43,6 +43,9 @@
// incidentd read file and gzip the data in bytes field
SECTION_GZIP = 5;
+
+ // incidentd calls tombstoned for annotated field
+ SECTION_TOMBSTONE = 6;
}
message SectionFlags {
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 44d9099..3dd6879 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -3002,6 +3002,7 @@
// from OMX_VIDEO_HEVCPROFILETYPE
public static final int HEVCProfileMain = 0x01;
public static final int HEVCProfileMain10 = 0x02;
+ public static final int HEVCProfileMainStill = 0x04;
public static final int HEVCProfileMain10HDR10 = 0x1000;
// from OMX_VIDEO_HEVCLEVELTYPE
@@ -3078,6 +3079,23 @@
* {@link VideoCapabilities} to determine the codec capabilities.
*/
public int level;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof CodecProfileLevel) {
+ CodecProfileLevel other = (CodecProfileLevel)obj;
+ return other.profile == profile && other.level == level;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(((long)profile << Integer.SIZE) | level);
+ }
};
/**
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index a9f72d0..2a3967c 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -223,6 +223,7 @@
* @see #onPositionChanged(MediaController2, long, long)
* @see #onBufferedPositionChanged(MediaController2, long)
*/
+ // TODO(jaewan): Use this (b/74316764)
public void onCurrentMediaItemChanged(@NonNull MediaController2 controller,
@NonNull MediaItem2 item) { }
@@ -230,43 +231,43 @@
* Called when a playlist is changed.
*
* @param controller the controller for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param list new playlist
* @param metadata new metadata
*/
public void onPlaylistChanged(@NonNull MediaController2 controller,
- @NonNull MediaPlaylistAgent mplc, @NonNull List<MediaItem2> list,
+ @NonNull MediaPlaylistAgent playlistAgent, @NonNull List<MediaItem2> list,
@Nullable MediaMetadata2 metadata) { }
/**
* Called when a playlist metadata is changed.
*
* @param controller the controller for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param metadata new metadata
*/
public void onPlaylistMetadataChanged(@NonNull MediaController2 controller,
- @NonNull MediaPlaylistAgent mplc, @Nullable MediaMetadata2 metadata) { }
+ @NonNull MediaPlaylistAgent playlistAgent, @Nullable MediaMetadata2 metadata) { }
/**
* Called when the shuffle mode is changed.
*
* @param controller the controller for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param shuffleMode repeat mode
* @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
* @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
* @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
*/
public void onShuffleModeChanged(@NonNull MediaController2 controller,
- @NonNull MediaPlaylistAgent mplc,
+ @NonNull MediaPlaylistAgent playlistAgent,
@MediaPlaylistAgent.ShuffleMode int shuffleMode) { }
/**
* Called when the repeat mode is changed.
*
* @param controller the controller for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param repeatMode repeat mode
* @see MediaPlaylistAgent#REPEAT_MODE_NONE
* @see MediaPlaylistAgent#REPEAT_MODE_ONE
@@ -274,7 +275,7 @@
* @see MediaPlaylistAgent#REPEAT_MODE_GROUP
*/
public void onRepeatModeChanged(@NonNull MediaController2 controller,
- @NonNull MediaPlaylistAgent mplc,
+ @NonNull MediaPlaylistAgent playlistAgent,
@MediaPlaylistAgent.RepeatMode int repeatMode) { }
/**
@@ -821,7 +822,9 @@
}
/**
- * Replace the media item at index in the playlist.
+ * Replace the media item at index in the playlist. This can be also used to update metadata of
+ * an item.
+ *
* @param index the index of the item to replace
* @param item the new item
*/
@@ -836,8 +839,7 @@
* @return index of the current item
*/
public MediaItem2 getCurrentMediaItem() {
- // TODO(jaewan): Rename provider API
- return mProvider.getCurrentPlaylistItem_impl();
+ return mProvider.getCurrentMediaItem_impl();
}
/**
@@ -852,13 +854,11 @@
}
public void skipToPreviousItem() {
- // TODO(jaewan): fix this
- mProvider.skipToPrevious_impl();
+ mProvider.skipToPreviousItem_impl();
}
public void skipToNextItem() {
- // TODO(jaewan): fix this
- mProvider.skipToNext_impl();
+ mProvider.skipToNextItem_impl();
}
public @RepeatMode int getRepeatMode() {
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 38c5389..6cab430 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -73,7 +73,7 @@
* Callback for the {@link MediaLibrarySession}.
*/
public static class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
- public MediaLibrarySessionCallback(Context context) {
+ public MediaLibrarySessionCallback(@NonNull Context context) {
super(context);
}
@@ -221,12 +221,12 @@
}
@Override
- public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent mplc) {
- return super.setPlaylistAgent(mplc);
+ public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) {
+ return super.setPlaylistAgent(playlistAgent);
}
@Override
- public Builder setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
+ public Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
return super.setVolumeProvider(volumeProvider);
}
@@ -236,12 +236,12 @@
}
@Override
- public Builder setId(String id) {
+ public Builder setId(@NonNull String id) {
return super.setId(id);
}
@Override
- public Builder setSessionCallback(@NonNull Executor executor,
+ public Builder setSessionCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull MediaLibrarySessionCallback callback) {
return super.setSessionCallback(executor, callback);
}
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index 502f929..fb12065 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -562,7 +562,7 @@
* @param key The key the value is stored under
* @return a CharSequence value, or null
*/
- public @Nullable CharSequence getText(@TextKey String key) {
+ public @Nullable CharSequence getText(@NonNull @TextKey String key) {
return mProvider.getText_impl(key);
}
@@ -611,7 +611,7 @@
* @param key The key the value is stored under
* @return A {@link Rating2} or {@code null}
*/
- public @Nullable Rating2 getRating(@RatingKey String key) {
+ public @Nullable Rating2 getRating(@NonNull @RatingKey String key) {
return mProvider.getRating_impl(key);
}
@@ -622,7 +622,7 @@
* @param key The key the value is stored under
* @return A {@link Bitmap} or null
*/
- public Bitmap getBitmap(@BitmapKey String key) {
+ public @Nullable Bitmap getBitmap(@NonNull @BitmapKey String key) {
return mProvider.getBitmap_impl(key);
}
@@ -749,7 +749,8 @@
* @param value The CharSequence value to store
* @return The Builder to allow chaining
*/
- public @NonNull Builder putText(@TextKey String key, @Nullable CharSequence value) {
+ public @NonNull Builder putText(@NonNull @TextKey String key,
+ @Nullable CharSequence value) {
return mProvider.putText_impl(key, value);
}
@@ -780,7 +781,8 @@
* @param value The String value to store
* @return The Builder to allow chaining
*/
- public @NonNull Builder putString(@TextKey String key, @Nullable String value) {
+ public @NonNull Builder putString(@NonNull @TextKey String key,
+ @Nullable String value) {
return mProvider.putString_impl(key, value);
}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 7c114df..ee1bb50 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -80,6 +80,7 @@
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -102,8 +103,6 @@
private boolean mScreenOnWhilePlaying;
private boolean mStayAwake;
private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
- private int mUsage = -1;
- private boolean mBypassInterruptionPolicy;
private final CloseGuard mGuard = CloseGuard.get();
private final Object mSrcLock = new Object();
@@ -117,6 +116,9 @@
private boolean mNextSourcePlayPending = false;
//--- guarded by |mSrcLock| end
+ private AtomicInteger mBufferedPercentageCurrent;
+ private AtomicInteger mBufferedPercentageNext;
+
// Modular DRM
private final Object mDrmLock = new Object();
//--- guarded by |mDrmLock| start
@@ -306,31 +308,38 @@
*/
@Override
public long getBufferedPosition() {
- // TODO: either get buffered position from native code, or cache BUFFERING_UPDATE
- // number and convert it to buffered position.
- return 0;
+ // Use cached buffered percent for now.
+ return getDuration() * mBufferedPercentageCurrent.get() / 100;
}
- /**
- * Gets the current player state.
- *
- * @return the current player state, one of the following:
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
- */
@Override
public @PlayerState int getPlayerState() {
- // TODO: use cached state or call native function.
- return PLAYER_STATE_IDLE;
+ int mediaplayer2State = getMediaPlayer2State();
+ int playerState;
+ switch (mediaplayer2State) {
+ case MEDIAPLAYER2_STATE_IDLE:
+ playerState = PLAYER_STATE_IDLE;
+ break;
+ case MEDIAPLAYER2_STATE_PREPARED:
+ case MEDIAPLAYER2_STATE_PAUSED:
+ playerState = PLAYER_STATE_PAUSED;
+ break;
+ case MEDIAPLAYER2_STATE_PLAYING:
+ playerState = PLAYER_STATE_PLAYING;
+ break;
+ case MEDIAPLAYER2_STATE_ERROR:
+ default:
+ playerState = PLAYER_STATE_ERROR;
+ break;
+ }
+
+ return playerState;
}
/**
* Gets the current buffering state of the player.
* During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
* buffered.
- * @return the buffering state, one of the following:
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
*/
@Override
public @BuffState int getBufferingState() {
@@ -352,9 +361,6 @@
final String msg = "Cannot set AudioAttributes to null";
throw new IllegalArgumentException(msg);
}
- mUsage = attributes.getUsage();
- mBypassInterruptionPolicy = (attributes.getAllFlags()
- & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
Parcel pattributes = Parcel.obtain();
attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
@@ -973,8 +979,10 @@
// Switch to next source only when it's in prepared state.
mCurrentDSD = mNextDSDs.get(0);
mCurrentSrcId = mNextSrcId;
+ mBufferedPercentageCurrent.set(mBufferedPercentageNext.get());
mNextDSDs.remove(0);
mNextSrcId = mSrcIdGenerator++; // make it different from mCurrentSrcId
+ mBufferedPercentageNext.set(0);
mNextSourceState = NEXT_SOURCE_STATE_INIT;
mNextSourcePlayPending = false;
@@ -2773,9 +2781,21 @@
{
final int percent = msg.arg1;
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE, percent));
+ if (srcId == mCurrentSrcId) {
+ mBufferedPercentageCurrent.set(percent);
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onInfo(
+ mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE,
+ percent));
+ }
+ } else if (srcId == mNextSrcId && !mNextDSDs.isEmpty()) {
+ mBufferedPercentageNext.set(percent);
+ DataSourceDesc nextDSD = mNextDSDs.get(0);
+ for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onInfo(
+ mMediaPlayer, nextDSD, MEDIA_INFO_BUFFERING_UPDATE,
+ percent));
+ }
}
}
return;
diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java
index 9238103..1d7520f 100644
--- a/media/java/android/media/MediaPlaylistAgent.java
+++ b/media/java/android/media/MediaPlaylistAgent.java
@@ -21,6 +21,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.media.update.ApiLoader;
+import android.media.update.MediaPlaylistAgentProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -92,7 +94,7 @@
*/
public static final int SHUFFLE_MODE_GROUP = 2;
- private MediaPlayerBase mPlayer;
+ private final MediaPlaylistAgentProvider mProvider;
/**
* A callback class to receive notifications for events on the media player. See
@@ -103,56 +105,55 @@
/**
* Called when a playlist is changed.
*
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param list new playlist
* @param metadata new metadata
*/
- public void onPlaylistChanged(@NonNull MediaPlaylistAgent mplc,
+ public void onPlaylistChanged(@NonNull MediaPlaylistAgent playlistAgent,
@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { }
/**
* Called when a playlist metadata is changed.
*
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param metadata new metadata
*/
- public void onPlaylistMetadataChanged(@NonNull MediaPlaylistAgent mplc,
+ public void onPlaylistMetadataChanged(@NonNull MediaPlaylistAgent playlistAgent,
@Nullable MediaMetadata2 metadata) { }
/**
* Called when the shuffle mode is changed.
*
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param shuffleMode repeat mode
* @see #SHUFFLE_MODE_NONE
* @see #SHUFFLE_MODE_ALL
* @see #SHUFFLE_MODE_GROUP
*/
- public void onShuffleModeChanged(@NonNull MediaPlaylistAgent mplc,
+ public void onShuffleModeChanged(@NonNull MediaPlaylistAgent playlistAgent,
@ShuffleMode int shuffleMode) { }
/**
* Called when the repeat mode is changed.
*
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param repeatMode repeat mode
* @see #REPEAT_MODE_NONE
* @see #REPEAT_MODE_ONE
* @see #REPEAT_MODE_ALL
* @see #REPEAT_MODE_GROUP
*/
- public void onRepeatModeChanged(@NonNull MediaPlaylistAgent mplc,
+ public void onRepeatModeChanged(@NonNull MediaPlaylistAgent playlistAgent,
@RepeatMode int repeatMode) { }
}
- public MediaPlaylistAgent(Context context) {
- // FYI, Need to have a context in the constructor for making this class be updatable
- // TODO(jaewan) : implement this
+ public MediaPlaylistAgent(@NonNull Context context) {
+ mProvider = ApiLoader.getProvider(context).createMediaPlaylistAgent(context, this);
}
/**
* Register {@link PlaylistEventCallback} to listen changes in the underlying
- * {@link MediaPlaylistAgent}, regardless of the change in the controller.
+ * {@link MediaPlaylistAgent}.
*
* @param executor a callback Executor
* @param callback a PlaylistEventCallback
@@ -160,7 +161,7 @@
*/
public final void registerPlaylistEventCallback(
@NonNull @CallbackExecutor Executor executor, @NonNull PlaylistEventCallback callback) {
- // TODO(jaewan): implement this
+ mProvider.registerPlaylistEventCallback_impl(executor, callback);
}
/**
@@ -169,25 +170,24 @@
* @param callback the callback to be removed
* @throws IllegalArgumentException if the callback is {@code null}.
*/
- public final void unregisterPlaylistEventCallback(
- @NonNull PlaylistEventCallback callback) {
- // TODO(jaewan): implement this
+ public final void unregisterPlaylistEventCallback(@NonNull PlaylistEventCallback callback) {
+ mProvider.unregisterPlaylistEventCallback_impl(callback);
}
public final void notifyPlaylistChanged() {
- // TODO(jaewan): implement this
+ mProvider.notifyPlaylistChanged_impl();
}
public final void notifyPlaylistMetadataChanged() {
- // TODO(jaewan): implement this
+ mProvider.notifyPlaylistMetadataChanged_impl();
}
public final void notifyShuffleModeChanged() {
- // TODO(jaewan): implement this
+ mProvider.notifyShuffleModeChanged_impl();
}
public final void notifyRepeatModeChanged() {
- // TODO(jaewan): implement this
+ mProvider.notifyRepeatModeChanged_impl();
}
/**
@@ -196,8 +196,7 @@
* @return playlist, or null if none is set.
*/
public @Nullable List<MediaItem2> getPlaylist() {
- // TODO(jaewan): implement this
- return null;
+ return mProvider.getPlaylist_impl();
}
/**
@@ -207,7 +206,7 @@
* @param metadata metadata of the playlist
*/
public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
- // TODO(jaewan): implement this
+ mProvider.setPlaylist_impl(list, metadata);
}
/**
@@ -216,8 +215,7 @@
* @return metadata metadata of the playlist, or null if none is set
*/
public @Nullable MediaMetadata2 getPlaylistMetadata() {
- // TODO(jaewan): implement this
- return null;
+ return mProvider.getPlaylistMetadata_impl();
}
/**
@@ -226,7 +224,7 @@
* @param metadata metadata of the playlist
*/
public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
- // TODO(jaewan): implement this
+ mProvider.updatePlaylistMetadata_impl(metadata);
}
/**
@@ -236,7 +234,7 @@
* @param item media item to add
*/
public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
- // TODO(jaewan): implement this
+ mProvider.addPlaylistItem_impl(index, item);
}
/**
@@ -245,19 +243,18 @@
* @param item media item to remove
*/
public void removePlaylistItem(@NonNull MediaItem2 item) {
- // TODO(jaewan): implement this
+ mProvider.removePlaylistItem_impl(item);
}
/**
- * Replaces the media item with the .
- * <p>
- * This can be used to update metadata of a MediaItem.
+ * Replace the media item at index in the playlist. This can be also used to update metadata of
+ * an item.
*
- * @param index index
- * @param item
+ * @param index the index of the item to replace
+ * @param item the new item
*/
public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
- // TODO(jaewan): implement this
+ mProvider.replacePlaylistItem_impl(index, item);
}
/**
@@ -266,15 +263,15 @@
* @param item media item to start playing from
*/
public void skipToPlaylistItem(@NonNull MediaItem2 item) {
- // TODO(jaewan): implement this
+ mProvider.skipToPlaylistItem_impl(item);
}
public void skipToPreviousItem() {
- // TODO(jaewan): implement this
+ mProvider.skipToPreviousItem_impl();
}
public void skipToNextItem() {
- // TODO(jaewan): implement this
+ mProvider.skipToNextItem_impl();
}
/**
@@ -287,8 +284,7 @@
* @see #REPEAT_MODE_GROUP
*/
public @RepeatMode int getRepeatMode() {
- // TODO(jaewan): implement this
- return REPEAT_MODE_NONE;
+ return mProvider.getRepeatMode_impl();
}
/**
@@ -301,7 +297,7 @@
* @see #REPEAT_MODE_GROUP
*/
public void setRepeatMode(@RepeatMode int repeatMode) {
- // TODO(jaewan): implement this
+ mProvider.setRepeatMode_impl(repeatMode);
}
/**
@@ -313,8 +309,7 @@
* @see #SHUFFLE_MODE_GROUP
*/
public @ShuffleMode int getShuffleMode() {
- // TODO(jaewan): implement this
- return SHUFFLE_MODE_NONE;
+ return mProvider.getShuffleMode_impl();
}
/**
@@ -326,6 +321,6 @@
* @see #SHUFFLE_MODE_GROUP
*/
public void setShuffleMode(@ShuffleMode int shuffleMode) {
- // TODO(jaewan): implement this
+ mProvider.setShuffleMode_impl(shuffleMode);
}
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index c309038..9d2c2828 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -324,7 +324,6 @@
private final Uri mAudioUri;
private final Uri mVideoUri;
private final Uri mImagesUri;
- private final Uri mThumbsUri;
private final Uri mPlaylistsUri;
private final Uri mFilesUri;
private final Uri mFilesUriNoNotify;
@@ -420,7 +419,6 @@
mAudioUri = Audio.Media.getContentUri(volumeName);
mVideoUri = Video.Media.getContentUri(volumeName);
mImagesUri = Images.Media.getContentUri(volumeName);
- mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
mFilesUri = Files.getContentUri(volumeName);
mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
@@ -1287,53 +1285,6 @@
}
}
- private void pruneDeadThumbnailFiles() {
- HashSet<String> existingFiles = new HashSet<String>();
- String directory = "/sdcard/DCIM/.thumbnails";
- String [] files = (new File(directory)).list();
- Cursor c = null;
- if (files == null)
- files = new String[0];
-
- for (int i = 0; i < files.length; i++) {
- String fullPathString = directory + "/" + files[i];
- existingFiles.add(fullPathString);
- }
-
- try {
- c = mMediaProvider.query(
- mThumbsUri,
- new String [] { "_data" },
- null,
- null,
- null, null);
- Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
- if (c != null && c.moveToFirst()) {
- do {
- String fullPathString = c.getString(0);
- existingFiles.remove(fullPathString);
- } while (c.moveToNext());
- }
-
- for (String fileToDelete : existingFiles) {
- if (false)
- Log.v(TAG, "fileToDelete is " + fileToDelete);
- try {
- (new File(fileToDelete)).delete();
- } catch (SecurityException ex) {
- }
- }
-
- Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
- } catch (RemoteException e) {
- // We will soon be killed...
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
static class MediaBulkDeleter {
StringBuilder whereClause = new StringBuilder();
ArrayList<String> whereArgs = new ArrayList<String>(100);
@@ -1377,9 +1328,6 @@
processPlayLists();
}
- if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
- pruneDeadThumbnailFiles();
-
// allow GC to clean up
mPlayLists.clear();
}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 4ad197a..65378b4 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -26,9 +26,8 @@
import android.media.MediaPlayerBase.BuffState;
import android.media.MediaPlayerBase.PlayerEventCallback;
import android.media.MediaPlayerBase.PlayerState;
-import android.media.session.MediaSession;
-import android.media.session.MediaSession.Callback;
-import android.media.session.PlaybackState;
+import android.media.MediaSession2.PlaylistParams.RepeatMode;
+import android.media.MediaSession2.PlaylistParams.ShuffleMode;
import android.media.update.ApiLoader;
import android.media.update.MediaSession2Provider;
import android.media.update.MediaSession2Provider.BuilderBaseProvider;
@@ -193,7 +192,7 @@
/**
* Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -202,7 +201,7 @@
/**
* Command code for {@link MediaController2#setShuffleMode(int)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -211,7 +210,7 @@
/**
* Command code for {@link MediaController2#setRepeatMode(int)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -220,7 +219,7 @@
/**
* Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -229,7 +228,7 @@
/**
* Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -238,7 +237,7 @@
/**
* Command code for {@link MediaController2#replacePlaylistItem(int, MediaItem2)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -248,7 +247,7 @@
* Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
* information to the controller.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -257,7 +256,7 @@
/**
* Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2).
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -270,7 +269,7 @@
* Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2)} and
* {@link MediaController2#updatePlaylistMetadata(MediaMetadata2)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -279,7 +278,7 @@
/**
* Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata2)}.
* <p>
- * Command would be sent directly to the playlist controller if the session doesn't reject the
+ * Command would be sent directly to the playlist agent if the session doesn't reject the
* request through the
* {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)}.
*/
@@ -416,10 +415,11 @@
public interface OnDataSourceMissingHelper {
/**
* Called when a {@link MediaItem2} in the playlist didn't have a {@link DataSourceDesc}
- * but it's needed now for preparing or playing it.
+ * but it's needed now for preparing or playing it. Returned data source descriptor will be
+ * sent to the player directly to prepare or play the contents.
* <p>
- * Returned data source descriptor will be sent to the player directly to prepare or play
- * the contents.
+ * An exception may be thrown if the returned {@link DataSourceDesc} is duplicated in the
+ * playlist, so items cannot be differentiated.
*
* @param session the session for this event
* @param item media item from the controller
@@ -490,7 +490,7 @@
* @return a new Command instance from the Bundle
* @hide
*/
- public static Command fromBundle(@NonNull Context context, Bundle command) {
+ public static Command fromBundle(@NonNull Context context, @NonNull Bundle command) {
return ApiLoader.getProvider(context).fromBundle_MediaSession2Command(context, command);
}
}
@@ -501,17 +501,17 @@
public static final class CommandGroup {
private final CommandGroupProvider mProvider;
- public CommandGroup(Context context) {
+ public CommandGroup(@NonNull Context context) {
mProvider = ApiLoader.getProvider(context)
.createMediaSession2CommandGroup(context, this, null);
}
- public CommandGroup(Context context, CommandGroup others) {
+ public CommandGroup(@NonNull Context context, @Nullable CommandGroup others) {
mProvider = ApiLoader.getProvider(context)
.createMediaSession2CommandGroup(context, this, others);
}
- public void addCommand(Command command) {
+ public void addCommand(@NonNull Command command) {
mProvider.addCommand_impl(command);
}
@@ -519,11 +519,11 @@
mProvider.addAllPredefinedCommands_impl();
}
- public void removeCommand(Command command) {
+ public void removeCommand(@NonNull Command command) {
mProvider.removeCommand_impl(command);
}
- public boolean hasCommand(Command command) {
+ public boolean hasCommand(@NonNull Command command) {
return mProvider.hasCommand_impl(command);
}
@@ -531,14 +531,14 @@
return mProvider.hasCommand_impl(code);
}
- public List<Command> getCommands() {
+ public @NonNull List<Command> getCommands() {
return mProvider.getCommands_impl();
}
/**
* @hide
*/
- public CommandGroupProvider getProvider() {
+ public @NonNull CommandGroupProvider getProvider() {
return mProvider;
}
@@ -546,7 +546,7 @@
* @return new bundle from the CommandGroup
* @hide
*/
- public Bundle toBundle() {
+ public @NonNull Bundle toBundle() {
return mProvider.toBundle_impl();
}
@@ -570,7 +570,10 @@
public static abstract class SessionCallback {
private final Context mContext;
- public SessionCallback(Context context) {
+ public SessionCallback(@NonNull Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("context shouldn't be null");
+ }
mContext = context;
}
@@ -584,7 +587,7 @@
*
* @param session the session for this event
* @param controller controller information.
- * @return allowed commands. Can be {@code null} to reject coonnection.
+ * @return allowed commands. Can be {@code null} to reject connection.
*/
public @Nullable CommandGroup onConnect(@NonNull MediaSession2 session,
@NonNull ControllerInfo controller) {
@@ -713,7 +716,7 @@
* <p>
* During the preparation, a session should not hold audio focus in order to allow other
* sessions play seamlessly. The state of playback should be updated to
- * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+ * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done.
* <p>
* The playback of the prepared content should start in the later calls of
* {@link MediaSession2#play()}.
@@ -738,9 +741,9 @@
* An empty query indicates that the app may prepare any music. The implementation should
* attempt to make a smart choice about what to play.
* <p>
- * The state of playback should be updated to {@link PlaybackState#STATE_PAUSED} after the
- * preparation is done. The playback of the prepared content should start in the later
- * calls of {@link MediaSession2#play()}.
+ * The state of playback should be updated to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}
+ * after the preparation is done. The playback of the prepared content should start in the
+ * later calls of {@link MediaSession2#play()}.
* <p>
* Override {@link #onPlayFromSearch} to handle requests for starting playback without
* preparation.
@@ -758,10 +761,10 @@
/**
* Called when a controller requested to prepare a specific media item represented by a URI
* through {@link MediaController2#prepareFromUri(Uri, Bundle)}.
- * <p></p>
+ * <p>
* During the preparation, a session should not hold audio focus in order to allow
* other sessions play seamlessly. The state of playback should be updated to
- * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+ * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done.
* <p>
* The playback of the prepared content should start in the later calls of
* {@link MediaSession2#play()}.
@@ -785,84 +788,85 @@
* callbacks.
*
* @param session the controller for this event
- * @param mpb the player for this event
+ * @param player the player for this event
* @param item new item
*/
+ // TODO(jaewan): Use this (b/74316764)
public void onCurrentMediaItemChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase mpb, @NonNull MediaItem2 item) { }
+ @NonNull MediaPlayerBase player, @NonNull MediaItem2 item) { }
/**
* Called when the player is <i>prepared</i>, i.e. it is ready to play the content
* referenced by the given data source.
* @param session the session for this event
- * @param mpb the player for this event
+ * @param player the player for this event
* @param item the media item for which buffering is happening
*/
- public void onMediaPrepared(@NonNull MediaSession2 session, @NonNull MediaPlayerBase mpb,
+ public void onMediaPrepared(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player,
@NonNull MediaItem2 item) { }
/**
* Called to indicate that the state of the player has changed.
* See {@link MediaPlayerBase#getPlayerState()} for polling the player state.
* @param session the session for this event
- * @param mpb the player for this event
+ * @param player the player for this event
* @param state the new state of the player.
*/
public void onPlayerStateChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase mpb, @PlayerState int state) { }
+ @NonNull MediaPlayerBase player, @PlayerState int state) { }
/**
* Called to report buffering events for a data source.
*
* @param session the session for this event
- * @param mpb the player for this event
+ * @param player the player for this event
* @param item the media item for which buffering is happening.
* @param state the new buffering state.
*/
public void onBufferingStateChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase mpb, @NonNull MediaItem2 item, @BuffState int state) { }
+ @NonNull MediaPlayerBase player, @NonNull MediaItem2 item, @BuffState int state) { }
/**
* Called when a playlist is changed.
*
* @param session the session for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param list new playlist
* @param metadata new metadata
*/
public void onPlaylistChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent mplc, @NonNull List<MediaItem2> list,
+ @NonNull MediaPlaylistAgent playlistAgent, @NonNull List<MediaItem2> list,
@Nullable MediaMetadata2 metadata) { }
/**
* Called when a playlist metadata is changed.
*
* @param session the session for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param metadata new metadata
*/
public void onPlaylistMetadataChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent mplc, @Nullable MediaMetadata2 metadata) { }
+ @NonNull MediaPlaylistAgent playlistAgent, @Nullable MediaMetadata2 metadata) { }
/**
* Called when the shuffle mode is changed.
*
* @param session the session for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param shuffleMode repeat mode
* @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
* @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
* @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
*/
public void onShuffleModeChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent mplc,
+ @NonNull MediaPlaylistAgent playlistAgent,
@MediaPlaylistAgent.ShuffleMode int shuffleMode) { }
/**
* Called when the repeat mode is changed.
*
* @param session the session for this event
- * @param mplc playlist controller for this event
+ * @param playlistAgent playlist agent for this event
* @param repeatMode repeat mode
* @see MediaPlaylistAgent#REPEAT_MODE_NONE
* @see MediaPlaylistAgent#REPEAT_MODE_ONE
@@ -870,7 +874,7 @@
* @see MediaPlaylistAgent#REPEAT_MODE_GROUP
*/
public void onRepeatModeChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent mplc,
+ @NonNull MediaPlaylistAgent playlistAgent,
@MediaPlaylistAgent.RepeatMode int repeatMode) { }
}
@@ -900,37 +904,39 @@
}
/**
- * Set the underlying {@link MediaPlayerBase} for this session to dispatch incoming event
+ * Sets the underlying {@link MediaPlayerBase} for this session to dispatch incoming event
* to.
- * <p>
*
* @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
*/
- U setPlayer(@NonNull MediaPlayerBase player) {
+ @NonNull U setPlayer(@NonNull MediaPlayerBase player) {
mProvider.setPlayer_impl(player);
return (U) this;
}
/**
- * Set the {@link MediaPlaylistAgent} for this session to manages playlist of the
- * underlying {@link MediaPlayerBase player}.
+ * Sets the {@link MediaPlaylistAgent} for this session to manages playlist of the
+ * underlying {@link MediaPlayerBase}. The playlist agent should manage
+ * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}.
+ * <p>
+ * If the {@link MediaPlaylistAgent} isn't set, session will create the default playlist
+ * agent.
*
- * @param mplc a {@link MediaPlaylistAgent} that manages playlist of the
- * {@code player.}
+ * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the
+ * {@code player}
*/
- U setPlaylistAgent(@NonNull MediaPlaylistAgent mplc) {
- // TODO(jaewan): fix this
- mProvider.setPlaylistController_impl(mplc);
+ U setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) {
+ mProvider.setPlaylistAgent_impl(playlistAgent);
return (U) this;
}
/**
- * Set the {@link VolumeProvider2} for this session to receive volume button events. If not
- * set, system will adjust the appropriate stream volume for this session's player.
+ * Sets the {@link VolumeProvider2} for this session to handle volume events. If not set,
+ * system will adjust the appropriate stream volume for this session's player.
*
* @param volumeProvider The provider that will receive volume button events.
*/
- U setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
+ @NonNull U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
mProvider.setVolumeProvider_impl(volumeProvider);
return (U) this;
}
@@ -942,7 +948,7 @@
*
* @param pi The intent to launch to show UI for this session.
*/
- U setSessionActivity(@Nullable PendingIntent pi) {
+ @NonNull U setSessionActivity(@Nullable PendingIntent pi) {
mProvider.setSessionActivity_impl(pi);
return (U) this;
}
@@ -957,7 +963,7 @@
* @throws IllegalArgumentException if id is {@code null}
* @return
*/
- U setId(@NonNull String id) {
+ @NonNull U setId(@NonNull String id) {
mProvider.setId_impl(id);
return (U) this;
}
@@ -969,7 +975,7 @@
* @param callback session callback.
* @return
*/
- U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull C callback) {
mProvider.setSessionCallback_impl(executor, callback);
return (U) this;
@@ -982,7 +988,7 @@
* @throws IllegalStateException if the session with the same id is already exists for the
* package.
*/
- T build() {
+ @NonNull T build() {
return mProvider.build_impl();
}
}
@@ -1002,38 +1008,38 @@
}
@Override
- public Builder setPlayer(@NonNull MediaPlayerBase player) {
+ public @NonNull Builder setPlayer(@NonNull MediaPlayerBase player) {
return super.setPlayer(player);
}
@Override
- public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent mplc) {
- return super.setPlaylistAgent(mplc);
+ public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) {
+ return super.setPlaylistAgent(playlistAgent);
}
@Override
- public Builder setVolumeProvider(@NonNull VolumeProvider2 volumeProvider) {
+ public @NonNull Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
return super.setVolumeProvider(volumeProvider);
}
@Override
- public Builder setSessionActivity(@Nullable PendingIntent pi) {
+ public @NonNull Builder setSessionActivity(@Nullable PendingIntent pi) {
return super.setSessionActivity(pi);
}
@Override
- public Builder setId(@NonNull String id) {
+ public @NonNull Builder setId(@NonNull String id) {
return super.setId(id);
}
@Override
- public Builder setSessionCallback(@NonNull Executor executor,
+ public @NonNull Builder setSessionCallback(@NonNull Executor executor,
@Nullable SessionCallback callback) {
return super.setSessionCallback(executor, callback);
}
@Override
- public MediaSession2 build() {
+ public @NonNull MediaSession2 build() {
return super.build();
}
}
@@ -1047,8 +1053,8 @@
/**
* @hide
*/
- public ControllerInfo(Context context, int uid, int pid, String packageName,
- IInterface callback) {
+ public ControllerInfo(@NonNull Context context, int uid, int pid,
+ @NonNull String packageName, @NonNull IInterface callback) {
mProvider = ApiLoader.getProvider(context)
.createMediaSession2ControllerInfo(
context, this, uid, pid, packageName, callback);
@@ -1057,7 +1063,7 @@
/**
* @return package name of the controller
*/
- public String getPackageName() {
+ public @NonNull String getPackageName() {
return mProvider.getPackageName_impl();
}
@@ -1082,7 +1088,7 @@
/**
* @hide
*/
- public ControllerInfoProvider getProvider() {
+ public @NonNull ControllerInfoProvider getProvider() {
return mProvider;
}
@@ -1168,7 +1174,7 @@
/**
* @hide
*/
- public CommandButtonProvider getProvider() {
+ public @NonNull CommandButtonProvider getProvider() {
return mProvider;
}
@@ -1183,27 +1189,27 @@
.createMediaSession2CommandButtonBuilder(context, this);
}
- public Builder setCommand(Command command) {
+ public @NonNull Builder setCommand(@Nullable Command command) {
return mProvider.setCommand_impl(command);
}
- public Builder setIconResId(int resId) {
+ public @NonNull Builder setIconResId(int resId) {
return mProvider.setIconResId_impl(resId);
}
- public Builder setDisplayName(String displayName) {
+ public @NonNull Builder setDisplayName(@Nullable String displayName) {
return mProvider.setDisplayName_impl(displayName);
}
- public Builder setEnabled(boolean enabled) {
+ public @NonNull Builder setEnabled(boolean enabled) {
return mProvider.setEnabled_impl(enabled);
}
- public Builder setExtras(Bundle extras) {
+ public @NonNull Builder setExtras(@Nullable Bundle extras) {
return mProvider.setExtras_impl(extras);
}
- public CommandButton build() {
+ public @NonNull CommandButton build() {
return mProvider.build_impl();
}
}
@@ -1345,10 +1351,13 @@
* Whenever it happens only one session was properly setup and others were all dummies.
* Android framework couldn't find the right session to dispatch media key event.
* 2. Simplify session's lifecycle.
- * {@link MediaSession} can be available after all of {@link MediaSession#setFlags(int)},
- * {@link MediaSession#setCallback(Callback)}, and
- * {@link MediaSession#setActive(boolean)}. It was common for an app to omit one, so
- * framework had to add heuristics to figure out if an app is
+ * {@link android.media.session.MediaSession} is available after all of
+ * {@link android.media.session.MediaSession#setFlags(int)},
+ * {@link android.media.session.MediaSession#setCallback(
+ * android.media.session.MediaSession.Callback)},
+ * and {@link android.media.session.MediaSession#setActive(boolean)}.
+ * It was common for an app to omit one, so framework had to add heuristics to figure out
+ * which should be the highest priority for handling media key event.
* @hide
*/
public MediaSession2(MediaSession2Provider provider) {
@@ -1359,24 +1368,28 @@
/**
* @hide
*/
- public MediaSession2Provider getProvider() {
+ public @NonNull MediaSession2Provider getProvider() {
return mProvider;
}
/**
- * Set the underlying {@link MediaPlayerBase} for this session to dispatch incoming event
- * to. Events from the {@link MediaController2} will be sent directly to the underlying
- * player on the {@link Handler} where the session is created on.
+ * Sets the underlying {@link MediaPlayerBase} and {@link MediaPlaylistAgent} for this session
+ * to dispatch incoming event to.
+ * <p>
+ * When a {@link MediaPlaylistAgent} is specified here, the playlist agent should manage
+ * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}.
+ * <p>
+ * If the {@link MediaPlaylistAgent} isn't set, session will recreate the default playlist
+ * agent.
*
- * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
- * @param mplc a {@link MediaPlaylistAgent} that manages playlist of the
- * {@code player}
- * @param volumeProvider The provider that will receive volume button events. If
- * {@code null}, system will adjust the appropriate stream volume for this session's player.
+ * @param player a {@link MediaPlayerBase} that handles actual media playback in your app
+ * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the {@code player}
+ * @param volumeProvider a {@link VolumeProvider2}. If {@code null}, system will adjust the
+ * appropriate stream volume for this session's player.
*/
public void updatePlayer(@NonNull MediaPlayerBase player,
- @Nullable MediaPlaylistAgent mplc, @Nullable VolumeProvider2 volumeProvider) {
- mProvider.updatePlayer_impl(player, mplc, volumeProvider);
+ @Nullable MediaPlaylistAgent playlistAgent, @Nullable VolumeProvider2 volumeProvider) {
+ mProvider.updatePlayer_impl(player, playlistAgent, volumeProvider);
}
@Override
@@ -1387,18 +1400,15 @@
/**
* @return player
*/
- public @NonNull
- MediaPlayerBase getPlayer() {
+ public @NonNull MediaPlayerBase getPlayer() {
return mProvider.getPlayer_impl();
}
/**
- * @return playlist manager
+ * @return playlist agent
*/
- public @Nullable
- MediaPlaylistAgent getPlaylistAgent() {
- // TODO(jaewan): implement this (b/74090741)
- return null;
+ public @NonNull MediaPlaylistAgent getPlaylistAgent() {
+ return mProvider.getPlaylistAgent_impl();
}
/**
@@ -1425,7 +1435,7 @@
*
* @param afr the full request parameters
*/
- public void setAudioFocusRequest(AudioFocusRequest afr) {
+ public void setAudioFocusRequest(@Nullable AudioFocusRequest afr) {
// TODO(jaewan): implement this (b/72529899)
// mProvider.setAudioFocusRequest_impl(focusGain);
}
@@ -1490,20 +1500,26 @@
/**
* Play playback
+ * <p>
+ * This calls {@link MediaPlayerBase#play()}.
*/
public void play() {
mProvider.play_impl();
}
/**
- * Pause playback
+ * Pause playback.
+ * <p>
+ * This calls {@link MediaPlayerBase#pause()}.
*/
public void pause() {
mProvider.pause_impl();
}
/**
- * Stop playback
+ * Stop playback, and reset the player to the initial state.
+ * <p>
+ * This calls {@link MediaPlayerBase#reset()}.
*/
public void stop() {
mProvider.stop_impl();
@@ -1513,8 +1529,10 @@
* Request that the player prepare its playback. In other words, other sessions can continue
* to play during the preparation of this session. This method can be used to speed up the
* start of the playback. Once the preparation is done, the session will change its playback
- * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
- * start playback.
+ * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called
+ * to start playback.
+ * <p>
+ * This calls {@link MediaPlayerBase#reset()}.
*/
public void prepare() {
mProvider.prepare_impl();
@@ -1666,15 +1684,15 @@
* The helper will be run on the executor that you've specified by the
* {@link Builder#setSessionCallback(Executor, SessionCallback)}.
*
- * @param helper a data source misisng helper.
- * @throws IllegalStateException when the helper is set when the playlist controller is set
+ * @param helper a data source missing helper.
+ * @throws IllegalStateException when the helper is set when the playlist agent is set
* @see #setPlaylist(List, MediaMetadata2)
* @see SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, Command)
* @see #COMMAND_CODE_PLAYLIST_ADD_ITEM
* @see #COMMAND_CODE_PLAYLIST_REPLACE_ITEM
*/
public void setOnDataSourceMissingHelper(@NonNull OnDataSourceMissingHelper helper) {
- // TODO(jaewan): Implement (b/74090741)
+ // TODO(jaewan): Implement (b/74090741).
}
/**
@@ -1708,17 +1726,19 @@
}
/**
- * Set a list of {@link MediaItem2} as the current play list.
+ * Set a list of {@link MediaItem2} as the current play list. Ensure uniqueness in the
+ * {@link MediaItem2} in the playlist so session can uniquely identity individual items.
* <p>
* You may specify a {@link MediaItem2} without {@link DataSourceDesc}. However, in that case,
* you should set {@link OnDataSourceMissingHelper} for player to prepare.
*
* @param list A list of {@link MediaItem2} objects to set as a play list.
- * @throws IllegalArgumentException if given {@param playlist} is null.
+ * @throws IllegalArgumentException if given list is {@code null}, or has duplicated media item.
* @see #setOnDataSourceMissingHelper
*/
public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
- // TODO(jaewan): Implement (b/74174649)
+ // TODO(jaewan): Handle metadata here (b/74174649)
+ // TODO(jaewan): Handle list change (b/74326040)
}
/**
@@ -1728,18 +1748,16 @@
* @throws IllegalArgumentException if the play list is null
* @throws NullPointerException if index is outside play list range
*/
- public void skipToPlaylistItem(MediaItem2 item) {
+ public void skipToPlaylistItem(@NonNull MediaItem2 item) {
mProvider.skipToPlaylistItem_impl(item);
}
public void skipToPreviousItem() {
- // TODO(jaewan): fix this
- mProvider.skipToPrevious_impl();
+ mProvider.skipToPreviousItem_impl();
}
public void skipToNextItem() {
- // TODO(jaewan): fix this
- mProvider.skipToNext_impl();
+ mProvider.skipToNextItem_impl();
}
public MediaMetadata2 getPlaylistMetadata() {
@@ -1770,12 +1788,14 @@
*
* @throws IllegalArgumentException if the play list is null
*/
- public void removePlaylistItem(MediaItem2 item) {
+ public void removePlaylistItem(@NonNull MediaItem2 item) {
mProvider.removePlaylistItem_impl(item);
}
/**
- * Replace the media item at index in the playlist.
+ * Replace the media item at index in the playlist. This can be also used to update metadata of
+ * an item.
+ *
* @param index the index of the item to replace
* @param item the new item
*/
@@ -1789,7 +1809,7 @@
* @return currently playing media item
*/
public MediaItem2 getCurrentMediaItem() {
- // TODO(jaewan): Rename provider API
+ // TODO(jaewan): Rename provider, and implement (b/74316764)
return mProvider.getCurrentPlaylistItem_impl();
}
@@ -1797,21 +1817,21 @@
// TODO(jaewan): Implement (b/74174649)
}
- public int getRepeatMode() {
+ public @RepeatMode int getRepeatMode() {
// TODO(jaewan): Implement (b/74118768)
return 0;
}
- public void setRepeatMode(int repeatMode) {
+ public void setRepeatMode(@RepeatMode int repeatMode) {
// TODO(jaewan): Implement (b/74118768)
}
- public int getShuffleMode() {
+ public @ShuffleMode int getShuffleMode() {
// TODO(jaewan): Implement (b/74118768)
return 0;
}
- public void setShuffleMode(int shuffleMode) {
+ public void setShuffleMode(@ShuffleMode int shuffleMode) {
// TODO(jaewan): Implement (b/74118768)
}
}
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index d352a86..32caf4b 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -166,7 +166,7 @@
*
* @return a {@link MediaNotification}. If it's {@code null}, notification wouldn't be shown.
*/
- public MediaNotification onUpdateNotification() {
+ public @Nullable MediaNotification onUpdateNotification() {
return mProvider.onUpdateNotification_impl();
}
@@ -202,7 +202,7 @@
}
/**
- * Returned by {@link #onUpdateNotification()} for making session service forground service
+ * Returned by {@link #onUpdateNotification()} for making session service foreground service
* to keep playback running in the background. It's highly recommended to show media style
* notification here.
*/
@@ -229,7 +229,7 @@
return mProvider.getNotificationId_impl();
}
- public Notification getNotification() {
+ public @NonNull Notification getNotification() {
return mProvider.getNotification_impl();
}
}
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 664308c..9899367 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -44,13 +44,14 @@
*/
public class MiniThumbFile {
private static final String TAG = "MiniThumbFile";
- private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+ private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
public static final int BYTES_PER_MINTHUMB = 10000;
private static final int HEADER_SIZE = 1 + 8 + 4;
private Uri mUri;
private RandomAccessFile mMiniThumbFile;
private FileChannel mChannel;
private ByteBuffer mBuffer;
+ private ByteBuffer mEmptyBuffer;
private static final Hashtable<String, MiniThumbFile> sThumbFiles =
new Hashtable<String, MiniThumbFile>();
@@ -127,9 +128,10 @@
return mMiniThumbFile;
}
- public MiniThumbFile(Uri uri) {
+ private MiniThumbFile(Uri uri) {
mUri = uri;
mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
+ mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
}
public synchronized void deactivate() {
@@ -184,6 +186,54 @@
return 0;
}
+ public synchronized void eraseMiniThumb(long id) {
+ RandomAccessFile r = miniThumbDataFile();
+ if (r != null) {
+ long pos = id * BYTES_PER_MINTHUMB;
+ FileLock lock = null;
+ try {
+ mBuffer.clear();
+ mBuffer.limit(1 + 8);
+
+ lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
+ // check that we can read the following 9 bytes
+ // (1 for the "status" and 8 for the long)
+ if (mChannel.read(mBuffer, pos) == 9) {
+ mBuffer.position(0);
+ if (mBuffer.get() == 1) {
+ long currentMagic = mBuffer.getLong();
+ if (currentMagic == 0) {
+ // there is no thumbnail stored here
+ Log.i(TAG, "no thumbnail for id " + id);
+ return;
+ }
+ // zero out the thumbnail slot
+ // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
+ // + " at offset " + pos);
+ mChannel.write(mEmptyBuffer, pos);
+ }
+ } else {
+ // Log.v(TAG, "No slot");
+ }
+ } catch (IOException ex) {
+ Log.v(TAG, "Got exception checking file magic: ", ex);
+ } catch (RuntimeException ex) {
+ // Other NIO related exception like disk full, read only channel..etc
+ Log.e(TAG, "Got exception when reading magic, id = " + id +
+ ", disk full or mount read-only? " + ex.getClass());
+ } finally {
+ try {
+ if (lock != null) lock.release();
+ }
+ catch (IOException ex) {
+ // ignore it.
+ }
+ }
+ } else {
+ // Log.v(TAG, "No data file");
+ }
+ }
+
public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
throws IOException {
RandomAccessFile r = miniThumbDataFile();
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
index e5b05fb..29bd922 100644
--- a/media/java/android/media/Rating2.java
+++ b/media/java/android/media/Rating2.java
@@ -152,7 +152,8 @@
* or {@link #RATING_PERCENTAGE}.
* @return null if an invalid rating style is passed, a new Rating2 instance otherwise.
*/
- public static @Nullable Rating2 newUnratedRating(@NonNull Context context, @Style int ratingStyle) {
+ public static @Nullable Rating2 newUnratedRating(@NonNull Context context,
+ @Style int ratingStyle) {
return ApiLoader.getProvider(context).newUnratedRating_Rating2(context, ratingStyle);
}
@@ -225,8 +226,7 @@
* {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
* or {@link #RATING_PERCENTAGE}.
*/
- @Style
- public int getRatingStyle() {
+ public @Style int getRatingStyle() {
return mProvider.getRatingStyle_impl();
}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 39cdcf0..fca0cc7 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -162,6 +162,11 @@
}
/** @hide */
+ public boolean isAffectingUsage(int usage) {
+ return mRule.isAffectingUsage(usage);
+ }
+
+ /** @hide */
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 866b574..749a45e 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -135,6 +135,17 @@
}
}
+ boolean isAffectingUsage(int usage) {
+ for (AudioMixMatchCriterion criterion : mCriteria) {
+ if ((criterion.mRule & RULE_MATCH_ATTRIBUTE_USAGE) != 0
+ && criterion.mAttr != null
+ && criterion.mAttr.getUsage() == usage) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static boolean areCriteriaEquivalent(ArrayList<AudioMixMatchCriterion> cr1,
ArrayList<AudioMixMatchCriterion> cr2) {
if (cr1 == null || cr2 == null) return false;
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index b928e93..0d190a7 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -16,6 +16,7 @@
package android.media.update;
+import android.annotation.NonNull;
import android.content.res.Resources;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -33,7 +34,10 @@
private ApiLoader() { }
- public static StaticProvider getProvider(Context context) {
+ public static StaticProvider getProvider(@NonNull Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("context shouldn't be null");
+ }
try {
return (StaticProvider) getMediaLibraryImpl(context);
} catch (PackageManager.NameNotFoundException | ReflectiveOperationException e) {
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index b3d4e0c..06e9544 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -70,7 +70,7 @@
long getPosition_impl();
float getPlaybackSpeed_impl();
long getBufferedPosition_impl();
- MediaItem2 getCurrentPlaylistItem_impl();
+ MediaItem2 getCurrentMediaItem_impl();
interface PlaybackInfoProvider {
int getPlaybackType_impl();
diff --git a/media/java/android/media/update/MediaPlaylistAgentProvider.java b/media/java/android/media/update/MediaPlaylistAgentProvider.java
new file mode 100644
index 0000000..b27d5a1
--- /dev/null
+++ b/media/java/android/media/update/MediaPlaylistAgentProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 android.media.update;
+
+import android.media.MediaItem2;
+import android.media.MediaMetadata2;
+import android.media.MediaPlaylistAgent.PlaylistEventCallback;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public interface MediaPlaylistAgentProvider {
+ // final methods of MediaPlaylistAgent
+ void registerPlaylistEventCallback_impl(Executor executor, PlaylistEventCallback callback);
+ void unregisterPlaylistEventCallback_impl(PlaylistEventCallback callback);
+ void notifyPlaylistChanged_impl();
+ void notifyPlaylistMetadataChanged_impl();
+ void notifyShuffleModeChanged_impl();
+ void notifyRepeatModeChanged_impl();
+
+ // public methods of MediaPlaylistAgent
+ List<MediaItem2> getPlaylist_impl();
+ void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
+ MediaMetadata2 getPlaylistMetadata_impl();
+ void updatePlaylistMetadata_impl(MediaMetadata2 metadata);
+ void addPlaylistItem_impl(int index, MediaItem2 item);
+ void removePlaylistItem_impl(MediaItem2 item);
+ void replacePlaylistItem_impl(int index, MediaItem2 item);
+ void skipToPlaylistItem_impl(MediaItem2 item);
+ void skipToPreviousItem_impl();
+ void skipToNextItem_impl();
+ int getRepeatMode_impl();
+ void setRepeatMode_impl(int repeatMode);
+ int getShuffleMode_impl();
+ void setShuffleMode_impl(int shuffleMode);
+}
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index af6133a..142650a 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -17,6 +17,7 @@
package android.media.update;
import android.app.PendingIntent;
+import android.media.AudioFocusRequest;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.MediaPlayerBase;
@@ -43,14 +44,15 @@
*/
public interface MediaSession2Provider extends TransportControlProvider {
void close_impl();
- void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistAgent mplc,
+ void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
VolumeProvider2 volumeProvider);
MediaPlayerBase getPlayer_impl();
+ MediaPlaylistAgent getPlaylistAgent_impl();
VolumeProvider2 getVolumeProvider_impl();
SessionToken2 getToken_impl();
List<ControllerInfo> getConnectedControllers_impl();
void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
- void setAudioFocusRequest_impl(int focusGain);
+ void setAudioFocusRequest_impl(AudioFocusRequest afr);
void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands);
void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
ResultReceiver receiver);
@@ -123,7 +125,7 @@
interface BuilderBaseProvider<T extends MediaSession2, C extends SessionCallback> {
void setPlayer_impl(MediaPlayerBase player);
- void setPlaylistController_impl(MediaPlaylistAgent mplc);
+ void setPlaylistAgent_impl(MediaPlaylistAgent playlistAgent);
void setVolumeProvider_impl(VolumeProvider2 volumeProvider);
void setSessionActivity_impl(PendingIntent pi);
void setId_impl(String id);
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 843fa71..53ced9c 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -30,6 +30,7 @@
import android.media.MediaLibraryService2.MediaLibrarySession;
import android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback;
import android.media.MediaMetadata2;
+import android.media.MediaPlaylistAgent;
import android.media.MediaSession2;
import android.media.MediaSession2.CommandButton.Builder;
import android.media.MediaSession2.PlaylistParams;
@@ -134,4 +135,7 @@
PlaybackState2Provider createPlaybackState2(Context context, PlaybackState2 instance, int state,
long position, long updateTime, float speed, long bufferedPosition, long activeItemId);
PlaybackState2 fromBundle_PlaybackState2(Context context, Bundle bundle);
+
+ MediaPlaylistAgentProvider createMediaPlaylistAgent(Context context,
+ MediaPlaylistAgent instance);
}
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
index 9af8ada..a3fb071 100644
--- a/media/java/android/media/update/TransportControlProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -26,8 +26,8 @@
void play_impl();
void pause_impl();
void stop_impl();
- void skipToPrevious_impl();
- void skipToNext_impl();
+ void skipToPreviousItem_impl();
+ void skipToNextItem_impl();
void prepare_impl();
void fastForward_impl();
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 11b3560..27b436f 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -69,19 +69,6 @@
void setSpeed_impl(float speed);
void setAudioFocusRequest_impl(int focusGain);
void setAudioAttributes_impl(AudioAttributes attributes);
- /**
- * @hide
- */
- void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerBase player);
- /**
- * @hide
- */
- // TODO: remove setRouteAttributes_impl with MediaSession.Callback once MediaSession2 is ready.
- void setRouteAttributes_impl(List<String> routeCategories, MediaSession.Callback sessionPlayer);
-
- /**
- * @hide TODO: remove
- */
void setVideoPath_impl(String path);
/**
* @hide TODO: remove
diff --git a/packages/CaptivePortalLogin/Android.mk b/packages/CaptivePortalLogin/Android.mk
index e6e0ad3..7dc23ff 100644
--- a/packages/CaptivePortalLogin/Android.mk
+++ b/packages/CaptivePortalLogin/Android.mk
@@ -2,6 +2,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
index 2324593..c292323 100644
--- a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
+++ b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
@@ -27,12 +27,17 @@
android:layout_height="wrap_content" />
</FrameLayout>
- <WebView
- android:id="@+id/webview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentBottom="false"
- android:layout_alignParentRight="false" />
+ <android.support.v4.widget.SwipeRefreshLayout
+ android:id="@+id/swipe_refresh"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <WebView
+ android:id="@+id/webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="false"
+ android:layout_alignParentRight="false" />
+ </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
</FrameLayout>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index e13aba7..4db0034 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -34,6 +34,7 @@
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
+import android.support.v4.widget.SwipeRefreshLayout;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TypedValue;
@@ -88,6 +89,7 @@
private ConnectivityManager mCm;
private boolean mLaunchBrowser = false;
private MyWebViewClient mWebViewClient;
+ private SwipeRefreshLayout mSwipeRefreshLayout;
// Ensures that done() happens once exactly, handling concurrent callers with atomic operations.
private final AtomicBoolean isDone = new AtomicBoolean(false);
@@ -159,6 +161,13 @@
// Start initial page load so WebView finishes loading proxy settings.
// Actual load of mUrl is initiated by MyWebViewClient.
webview.loadData("", "text/html", null);
+
+ mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
+ mSwipeRefreshLayout.setOnRefreshListener(() -> {
+ webview.reload();
+ mSwipeRefreshLayout.setRefreshing(true);
+ });
+
}
// Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
@@ -393,6 +402,7 @@
public void onPageFinished(WebView view, String url) {
mPagesLoaded++;
getProgressBar().setVisibility(View.INVISIBLE);
+ mSwipeRefreshLayout.setRefreshing(false);
if (mPagesLoaded == 1) {
// Now that WebView has loaded at least one page we know it has read in the proxy
// settings. Now prompt the WebView read the Network-specific proxy settings.
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 3c2ca2d..15b50d7 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -34,21 +34,21 @@
# Include support-v7-appcompat, if not already included
ifeq (,$(findstring android-support-v7-appcompat,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
endif
# Include support-v7-recyclerview, if not already included
ifeq (,$(findstring android-support-v7-recyclerview,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/recyclerview/res
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.recyclerview
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
endif
# Include android-support-v7-preference, if not already included
ifeq (,$(findstring android-support-v7-preference,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/preference/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/preference/res
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.preference
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-preference
endif
diff --git a/core/res/res/color/control_nodisable_material.xml b/packages/SettingsLib/res/color/batterymeter_plus_color.xml
similarity index 85%
copy from core/res/res/color/control_nodisable_material.xml
copy to packages/SettingsLib/res/color/batterymeter_plus_color.xml
index 4a73e93..949bede 100644
--- a/core/res/res/color/control_nodisable_material.xml
+++ b/packages/SettingsLib/res/color/batterymeter_plus_color.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2018 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.
@@ -13,7 +13,6 @@
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:color="?attr/colorControlNormal" />
+ <item android:color="?android:attr/colorError" />
</selector>
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 4fe9d56..e2f279a9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -54,6 +54,7 @@
private int mLevel = -1;
private boolean mCharging;
private boolean mPowerSaveEnabled;
+ private boolean mPowerSaveAsColorError = true;
private boolean mShowPercent;
private static final boolean SINGLE_DIGIT_PERCENT = false;
@@ -150,7 +151,8 @@
mBoltPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_bolt_color));
mBoltPoints = loadPoints(res, R.array.batterymeter_bolt_points);
- mPlusPaint = new Paint(mBoltPaint);
+ mPlusPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPlusPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_plus_color));
mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
@@ -195,6 +197,10 @@
postInvalidate();
}
+ protected void setPowerSaveAsColorError(boolean asError) {
+ mPowerSaveAsColorError = asError;
+ }
+
// an approximation of View.postInvalidate()
protected void postInvalidate() {
unscheduleSelf(this::invalidateSelf);
@@ -254,10 +260,6 @@
}
private int getColorForLevel(int percent) {
- // If we are in power save mode, always use the normal color.
- if (mPowerSaveEnabled) {
- return mIconTint;
- }
int thresh, color = 0;
for (int i = 0; i < mColors.length; i += 2) {
thresh = mColors[i];
@@ -279,7 +281,6 @@
mIconTint = fillColor;
mFramePaint.setColor(backgroundColor);
mBoltPaint.setColor(fillColor);
- mPlusPaint.setColor(fillColor);
mChargeColor = fillColor;
invalidateSelf();
}
@@ -392,14 +393,16 @@
mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
}
- float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
- boltPct = Math.min(Math.max(boltPct, 0), 1);
- if (boltPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the bolt if opaque
+ float fillPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
+ fillPct = Math.min(Math.max(fillPct, 0), 1);
+ if (fillPct <= BOLT_LEVEL_THRESHOLD) {
+ // draw the plus if opaque
c.drawPath(mPlusPath, mPlusPaint);
} else {
- // otherwise cut the bolt out of the overall shape
mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+ if (mPowerSaveAsColorError) {
+ c.drawPath(mPlusPath, mPlusPaint);
+ }
}
}
diff --git a/packages/StatementService/src/com/android/statementservice/DirectStatementService.java b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
index 449738e..659696e 100644
--- a/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
+++ b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
@@ -155,17 +155,20 @@
@Override
public void onDestroy() {
super.onDestroy();
- if (mThread != null) {
- mThread.quit();
- }
-
- try {
- if (mHttpResponseCache != null) {
- mHttpResponseCache.delete();
+ final HttpResponseCache responseCache = mHttpResponseCache;
+ mHandler.post(new Runnable() {
+ public void run() {
+ try {
+ if (responseCache != null) {
+ responseCache.delete();
+ }
+ } catch (IOException e) {
+ Log.i(TAG, "HTTP(S) response cache deletion failed:" + e);
+ }
+ Looper.myLooper().quit();
}
- } catch (IOException e) {
- Log.i(TAG, "HTTP(S) response cache deletion failed:" + e);
- }
+ });
+ mHttpResponseCache = null;
}
@Override
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index ecc2ff4..299e337 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -70,6 +70,11 @@
*/
public MenuItem getLongpressMenuItem(Context context);
+ /**
+ * @return the {@link MenuItem} to display when app ops icons are pressed.
+ */
+ public MenuItem getAppOpsMenuItem(Context context);
+
public void setMenuItems(ArrayList<MenuItem> items);
public void setMenuClickListener(OnMenuEventListener listener);
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 828c9df..611aa43 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -22,7 +22,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clipToPadding="false"
@@ -37,7 +37,8 @@
android:textColor="?attr/wallpaperTextColor"
android:theme="@style/TextAppearance.Keyguard"
/>
- <LinearLayout android:id="@+id/row"
+ <view class="com.android.keyguard.KeyguardSliceView$Row"
+ android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
diff --git a/packages/SystemUI/res/anim/ic_qs_signal_blink_1.xml b/packages/SystemUI/res/anim/ic_qs_signal_blink_1.xml
deleted file mode 100644
index 57b61da..0000000
--- a/packages/SystemUI/res/anim/ic_qs_signal_blink_1.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
- 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.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/linear_interpolator"
- android:duration="@integer/carrier_network_change_anim_time"
- android:repeatCount="-1">
-
- <propertyValuesHolder
- android:propertyName="fillColor"
- android:valueType="colorType">
- <keyframe
- android:fraction="0.0"
- android:value="#FFFFFFFF"/>
- <keyframe
- android:fraction="0.32"
- android:value="#FFFFFFFF"/>
- <keyframe
- android:fraction="0.33"
- android:value="#4DFFFFFF"/>
- <keyframe
- android:fraction="1.0"
- android:value="#4DFFFFFF"/>
- </propertyValuesHolder>
-
-</objectAnimator>
diff --git a/packages/SystemUI/res/anim/ic_qs_signal_blink_2.xml b/packages/SystemUI/res/anim/ic_qs_signal_blink_2.xml
deleted file mode 100644
index 09694c3..0000000
--- a/packages/SystemUI/res/anim/ic_qs_signal_blink_2.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<!--
- 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.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/linear_interpolator"
- android:duration="@integer/carrier_network_change_anim_time"
- android:repeatCount="-1">
-
- <propertyValuesHolder
- android:propertyName="fillColor"
- android:valueType="colorType">
- <keyframe
- android:fraction="0.0"
- android:value="#4DFFFFFF"/>
- <keyframe
- android:fraction="0.32"
- android:value="#4DFFFFFF"/>
- <keyframe
- android:fraction="0.33"
- android:value="#FFFFFFFF"/>
- <keyframe
- android:fraction="0.66"
- android:value="#FFFFFFFF"/>
- <keyframe
- android:fraction="0.67"
- android:value="#4DFFFFFF"/>
- <keyframe
- android:fraction="1.0"
- android:value="#4DFFFFFF"/>
- </propertyValuesHolder>
-
-</objectAnimator>
diff --git a/packages/SystemUI/res/anim/ic_qs_signal_blink_3.xml b/packages/SystemUI/res/anim/ic_qs_signal_blink_3.xml
deleted file mode 100644
index 2270e3f..0000000
--- a/packages/SystemUI/res/anim/ic_qs_signal_blink_3.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
- 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.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/linear_interpolator"
- android:duration="@integer/carrier_network_change_anim_time"
- android:repeatCount="-1">
-
- <propertyValuesHolder
- android:propertyName="fillColor"
- android:valueType="colorType">
- <keyframe
- android:fraction="0.0"
- android:value="#4DFFFFFF"/>
- <keyframe
- android:fraction="0.66"
- android:value="#4DFFFFFF"/>
- <keyframe
- android:fraction="0.67"
- android:value="#FFFFFFFF"/>
- <keyframe
- android:fraction="1.0"
- android:value="#FFFFFFFF"/>
- </propertyValuesHolder>
-
-</objectAnimator>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
new file mode 100644
index 0000000..221f170
--- /dev/null
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2018 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">
+ <solid android:color="@color/fingerprint_dialog_bg_color" />
+ <corners android:radius="1dp"
+ android:topLeftRadius="@dimen/fingerprint_dialog_corner_size"
+ android:topRightRadius="@dimen/fingerprint_dialog_corner_size"
+ android:bottomLeftRadius="0dp"
+ android:bottomRightRadius="0dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
new file mode 100644
index 0000000..382d9d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M4,7h4v10H6V9H4V7z M15.83,11.72L18.66,7h-2.33l-1.66,2.77L13,7h-2.33l2.83,4.72L10.33,17h2.33l2-3.34l2,3.34H19 L15.83,11.72z" />
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
new file mode 100644
index 0000000..ce003e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M3,7v2h5v2H4v2h4v2H3v2h5c1.1,0,2-0.9,2-2v-1.5c0-0.83-0.67-1.5-1.5-1.5c0.83,0,1.5-0.67,1.5-1.5V9c0-1.1-0.9-2-2-2H3z M21,11v4c0,1.1-0.9,2-2,2h-5c-1.1,0-2-0.9-2-2V9c0-1.1,0.9-2,2-2h5c1.1,0,2,0.9,2,2h-2h-5v6h5v-2h-2.5v-2H21z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
new file mode 100644
index 0000000..8e22e06
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M9,7H7v5H5V7H3v7h4v3h2v-3h2v-2H9V7z M17,11v2h2v2h-5V9h7c0-1.1-0.9-2-2-2h-5c-1.1,0-2,0.9-2,2v6c0,1.1,0.9,2,2,2h5 c1.1,0,2-0.9,2-2v-4H17z" />
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
new file mode 100644
index 0000000..32add0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13,11v2h2v2h-4V9h6c0-1.1-0.9-2-2-2h-4C9.9,7,9,7.9,9,9v6c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4H13z M24,11h-2V9h-2v2h-2v2 h2v2h2v-2h2V11z M7,7H5v5H3V7H1v7h4v3h2v-3h1v-2H7V7z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
new file mode 100644
index 0000000..80e507b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 16 9 L 16 7 L 8 7 L 8 17 L 16 17 L 16 15 L 10 15 L 10 13 L 16 13 L 16 11 L 10 11 L 10 9 Z" />
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
new file mode 100644
index 0000000..04049ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,11v2h2v2H9V9h0.44H14h2c0-1.1-0.9-2-2-2H9C7.9,7,7,7.9,7,9v6c0,1.1,0.9,2,2,2h5c1.1,0,2-0.9,2-2v-4H12z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
new file mode 100644
index 0000000..31cc4a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M15,11H9V7H7v10h2v-4h6v4h2V7h-2V11z" />
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
new file mode 100644
index 0000000..ca1020e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,11H6V7H4v10h2v-4h6v4h2V7h-2V11z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M22,11h-2V9h-2v2h-2v2h2v2h2v-2h2V11z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
new file mode 100644
index 0000000..5d90965
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6,14h3v2H4V8h2V14z M9,10h2v6h2v-6h2V8H9V10z M21,10V8h-5v8h2h3v-2h-3v-0.67V13h3v-2h-3v-1H21z" />
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
new file mode 100644
index 0000000..0366e24
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2018 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">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M3,14h3v2H1V8h2V14z M5,10h2v6h2v-6h2V8H5V10z M12,16h5v-2h-3v-1h3v-2h-3v-1h3V8h-5V16z M24,11h-2V9h-2v2h-2v2h2v2h2v-2h2 V11z" />
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
deleted file mode 100644
index 8908975..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="12dp"
- android:height="24.0dp"
- android:viewportWidth="20.0"
- android:viewportHeight="40.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
deleted file mode 100644
index b78d3bf..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
- android:fillAlpha="0.3"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
deleted file mode 100644
index 5217748..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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="12.0dp"
- android:height="24dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
deleted file mode 100644
index 546a96f..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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="15dp"
- android:height="24dp"
- android:viewportWidth="15.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
deleted file mode 100644
index 26b68c7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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="12.0dp"
- android:height="24dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M11.900000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.100000,9.000000 6.100000,7.900000L6.100000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000S8.100000,2.400000 9.000000,2.400000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S9.500000,3.700000 9.000000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S7.700000,5.000000 7.700000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.099999,7.800000L9.000000,7.800000L9.000000,6.600000l2.900000,0.000000L11.900000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
deleted file mode 100644
index 6e4b4c5..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15.0dp"
- android:height="20.0dp"
- android:viewportWidth="18.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M11.9,9.9c-0.2,0.4 -0.6,0.7 -1.0,0.9s-1.0,0.4 -1.8,0.4c-0.9,0.0 -1.7,-0.3 -2.2,-0.8S6.1,9.0 6.1,7.9L6.1,5.6c0.0,-1.1 0.3,-1.9 0.8,-2.4S8.2,2.4 9.0,2.4c1.0,0.0 1.7,0.2 2.1,0.7s0.7,1.2 0.7,2.1l-1.6,0.0c0.0,-0.5 -0.1,-0.9 -0.2,-1.1S9.5,3.7 9.0,3.7c-0.4,0.0 -0.7,0.2 -0.9,0.5S7.8,5.0 7.8,5.6l0.0,2.3c0.0,0.7 0.1,1.1 0.3,1.4c0.2,0.3 0.6,0.5 1.0,0.5c0.3,0.0 0.6,0.0 0.7,-0.1s0.3,-0.2 0.4,-0.3L10.2,7.8L9.0,7.8L9.0,6.6l2.9,0.0L11.9,9.9z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M17.7,4.4l-1.900001,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.900001,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
deleted file mode 100644
index c841a66..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- 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="M21.799999,22.299999l-1.199999,-1.299999 0.000000,0.000000 -9.600000,-10.000000 0.000000,0.000000 -6.400000,-6.700000 -1.300000,1.300000 6.400000,6.700000 -8.700000,8.700000 16.900000,0.000000 2.600000,2.700001z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,1.000000l-8.600000,8.600000 8.600000,9.100000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
deleted file mode 100644
index f4b6ed8..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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="12dp"
- android:height="24dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <group
- android:translateX="3.5" >
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
deleted file mode 100644
index 60a7f1e9..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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="12dp"
- android:height="24dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <group android:translateX="3.5" >
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
deleted file mode 100644
index 4ffb4be..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 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="12dp"
- android:height="24dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <group
- android:translateX="3.5" >
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
deleted file mode 100644
index 816cd32..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2014 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="11.9dp"
- android:height="22dp"
- android:viewportWidth="13.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.300000,3.800000L7.000000,3.800000L7.000000,11.000000L5.300000,11.000000L5.300000,3.800000L4.000000,3.800000L4.000000,2.500000l4.300000,0.000000L8.300000,3.800000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.400000,7.300000l-1.700000,0.000000l0.000000,2.400000l2.100000,0.000000L12.799999,11.000000L9.000000,11.000000L9.000000,2.500000l3.700000,0.000000l0.000000,1.300000l-2.100000,0.000000l0.000000,2.100000l1.700000,0.000000L12.300000,7.300000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
deleted file mode 100644
index 4c43e13..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="15.0dp"
- android:height="19.5dp"
- android:viewportWidth="18.5"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.3,3.8L7.0,3.8L7.0,11.0L5.4,11.0L5.4,3.8L4.0,3.8L4.0,2.5l4.3,0.0L8.3,3.8z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.4,7.3l-1.7,0.0l0.0,2.4l2.1,0.0L12.799999,11.0L9.0,11.0L9.0,2.5l3.7,0.0l0.0,1.3l-2.1,0.0l0.0,2.1l1.7,0.0L12.4,7.3L12.4,7.3z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18.4,4.4l-1.9,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.9,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml b/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
deleted file mode 100644
index c8c857c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 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:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,22.000000l20.000000,0.000000L22.000000,2.000000L2.000000,22.000000zM20.000000,20.000000L6.800000,20.000000L20.000000,6.800000L20.000000,20.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_swap_vert.xml b/packages/SystemUI/res/drawable/ic_swap_vert.xml
new file mode 100644
index 0000000..eed79ff
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_swap_vert.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3V14h2V6.99h3L9 3z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/rounded_bg_full.xml b/packages/SystemUI/res/drawable/rounded_bg_full.xml
index a6f40fa..03f18bb 100644
--- a/packages/SystemUI/res/drawable/rounded_bg_full.xml
+++ b/packages/SystemUI/res/drawable/rounded_bg_full.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?android:attr/colorPrimary" />
+ <solid android:color="?android:attr/colorBackgroundFloating" />
<corners
android:bottomLeftRadius="@dimen/corner_size"
android:topLeftRadius="@dimen/corner_size"
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
deleted file mode 100644
index ea794d4..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="40.0"
- android:viewportHeight="40.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
deleted file mode 100644
index d7463a4..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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="8.5dp"
- android:height="17dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
deleted file mode 100644
index 6309b6d..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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="9.208dp"
- android:height="17dp"
- android:viewportWidth="13.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
deleted file mode 100644
index 4067ae5..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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="8.5dp"
- android:height="17dp"
- android:viewportWidth="12.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M11.900000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.100000,9.000000 6.100000,7.900000L6.100000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000S8.100000,2.400000 9.000000,2.400000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S9.500000,3.700000 9.000000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S7.700000,5.000000 7.700000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.099999,7.800000L9.000000,7.800000L9.000000,6.600000l2.900000,0.000000L11.900000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
deleted file mode 100644
index 719a6ca..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g_plus.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="10.5dp"
- android:height="14.0dp"
- android:viewportWidth="18.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M11.9,9.9c-0.2,0.4 -0.6,0.7 -1.0,0.9s-1.0,0.4 -1.8,0.4c-0.9,0.0 -1.7,-0.3 -2.2,-0.8S6.1,9.0 6.1,7.9L6.1,5.6c0.0,-1.1 0.3,-1.9 0.8,-2.4S8.2,2.4 9.0,2.4c1.0,0.0 1.7,0.2 2.1,0.7s0.7,1.2 0.7,2.1l-1.6,0.0c0.0,-0.5 -0.1,-0.9 -0.2,-1.1S9.5,3.7 9.0,3.7c-0.4,0.0 -0.7,0.2 -0.9,0.5S7.8,5.0 7.8,5.6l0.0,2.3c0.0,0.7 0.1,1.1 0.3,1.4c0.2,0.3 0.6,0.5 1.0,0.5c0.3,0.0 0.6,0.0 0.7,-0.1s0.3,-0.2 0.4,-0.3L10.2,7.8L9.0,7.8L9.0,6.6l2.9,0.0L11.9,9.9z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M17.7,4.4l-1.900001,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.900001,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
deleted file mode 100644
index acaa9b1..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 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="3.541dp"
- android:height="17dp"
- android:viewportWidth="5.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
deleted file mode 100644
index 7985237..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 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="4.958dp"
- android:height="17dp"
- android:viewportWidth="7.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
deleted file mode 100644
index fda8761..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 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="4.25dp"
- android:height="17dp"
- android:viewportWidth="6.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
deleted file mode 100644
index c08ff20..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-Copyright (C) 2014 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="9.208dp"
- android:height="17dp"
- android:viewportWidth="13.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.300000,3.800000L7.000000,3.800000L7.000000,11.000000L5.300000,11.000000L5.300000,3.800000L4.000000,3.800000L4.000000,2.500000l4.300000,0.000000L8.300000,3.800000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.400000,7.300000l-1.700000,0.000000l0.000000,2.400000l2.100000,0.000000L12.799999,11.000000L9.000000,11.000000L9.000000,2.500000l3.700000,0.000000l0.000000,1.300000l-2.100000,0.000000l0.000000,2.100000l1.700000,0.000000L12.300000,7.300000z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml
deleted file mode 100644
index 62159b3..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte_plus.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="11.08dp"
- android:height="14.0dp"
- android:viewportWidth="19.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.3,3.8L7.0,3.8L7.0,11.0L5.4,11.0L5.4,3.8L4.0,3.8L4.0,2.5l4.3,0.0L8.3,3.8z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.4,7.3l-1.7,0.0l0.0,2.4l2.1,0.0L12.799999,11.0L9.0,11.0L9.0,2.5l3.7,0.0l0.0,1.3l-2.1,0.0l0.0,2.1l1.7,0.0L12.4,7.3L12.4,7.3z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18.4,4.4l-1.9,0.0 0.0,-1.9 -1.2,0.0 0.0,1.9 -1.900001,0.0 0.0,1.2 1.900001,0.0 0.0,1.9 1.2,0.0 0.0,-1.9 1.9,0.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml
new file mode 100644
index 0000000..74a4c6e
--- /dev/null
+++ b/packages/SystemUI/res/layout/app_ops_info.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018, 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.
+-->
+
+<com.android.systemui.statusbar.AppOpsInfo
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/app_ops_info"
+ android:clickable="true"
+ android:orientation="vertical"
+ android:paddingStart="@*android:dimen/notification_content_margin_start"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end"
+ android:background="@color/notification_guts_bg_color"
+ android:theme="@*android:style/Theme.DeviceDefault.Light">
+
+ <!-- Package Info -->
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layout_marginTop="@*android:dimen/notification_header_padding_top" >
+ <ImageView
+ android:id="@+id/pkgicon"
+ android:layout_width="@dimen/notification_guts_header_height"
+ android:layout_height="@dimen/notification_guts_header_height"
+ android:layout_centerVertical="true"
+ android:layout_marginEnd="3dp" />
+ <TextView
+ android:id="@+id/pkgname"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
+ android:layout_marginStart="3dp"
+ android:layout_marginEnd="2dp"
+ android:singleLine="true"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@id/pkgicon" />
+ </RelativeLayout>
+
+ <TextView
+ android:id="@+id/prompt"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@*android:dimen/notification_header_padding_top"
+ style="@style/TextAppearance.NotificationInfo.Secondary" />
+
+ <!-- Settings and Done buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="@dimen/notification_guts_button_spacing"
+ android:layout_marginBottom="@dimen/notification_guts_button_spacing"
+ android:gravity="end" >
+
+ <TextView
+ android:id="@+id/settings"
+ android:text="@string/notification_appops_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="@drawable/ripple_drawable"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/ok"
+ android:text="@string/notification_appops_ok"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="@drawable/ripple_drawable"
+ android:minWidth="48dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="-8dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </LinearLayout>
+</com.android.systemui.statusbar.AppOpsInfo>
diff --git a/packages/SystemUI/res/layout/data_usage.xml b/packages/SystemUI/res/layout/data_usage.xml
index fdc6f14..0d59369 100644
--- a/packages/SystemUI/res/layout/data_usage.xml
+++ b/packages/SystemUI/res/layout/data_usage.xml
@@ -88,7 +88,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="16dp"
- android:text="@string/accessibility_data_connection_roaming"
+ android:text="@string/data_connection_roaming"
android:textAppearance="@style/TextAppearance.QS.DataUsage.Secondary"
android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/fingerprint_dialog.xml
index f02c0ba..1b47489 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/fingerprint_dialog.xml
@@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:elevation="2dp"
- android:background="@color/fingerprint_dialog_bg_color">
+ android:background="@drawable/fingerprint_dialog_bg">
<TextView
android:id="@+id/title"
@@ -45,7 +45,7 @@
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
- android:gravity="center"
+ android:gravity="@integer/fingerprint_dialog_text_gravity"
android:textSize="20sp"
android:maxLines="1"
android:singleLine="true"
@@ -57,16 +57,16 @@
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
+ android:layout_marginTop="8dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
- android:gravity="center_horizontal"
- android:textSize="14sp"
+ android:gravity="@integer/fingerprint_dialog_text_gravity"
+ android:textSize="16sp"
android:maxLines="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
- android:textColor="@color/fingerprint_dialog_text_light_color"/>
+ android:textColor="@color/fingerprint_dialog_text_dark_color"/>
<TextView
android:id="@+id/description"
@@ -74,7 +74,8 @@
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
- android:paddingTop="24dp"
+ android:gravity="@integer/fingerprint_dialog_text_gravity"
+ android:paddingTop="8dp"
android:textSize="16sp"
android:maxLines="4"
android:textColor="@color/fingerprint_dialog_text_dark_color"/>
@@ -84,7 +85,7 @@
android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
android:layout_gravity="center_horizontal"
- android:layout_marginTop="32dp"
+ android:layout_marginTop="48dp"
android:scaleType="fitXY"
android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
@@ -106,7 +107,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="72dip"
- android:paddingTop="16dp"
+ android:paddingTop="24dp"
android:layout_gravity="center_vertical"
style="?android:attr/buttonBarStyle"
android:orientation="horizontal"
diff --git a/packages/SystemUI/res/layout/global_actions_item.xml b/packages/SystemUI/res/layout/global_actions_item.xml
index 0d735e7..bf3aea8 100644
--- a/packages/SystemUI/res/layout/global_actions_item.xml
+++ b/packages/SystemUI/res/layout/global_actions_item.xml
@@ -33,7 +33,9 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
- android:scaleType="center"/>
+ android:scaleType="center"
+ android:alpha="?android:attr/primaryContentAlpha"
+ />
<TextView
android:id="@*android:id/message"
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index 43aa8ab..4a6af9e 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -17,7 +17,7 @@
android:layout_gravity="top|right"
android:gravity="center"
android:orientation="vertical"
- android:padding="12dp"
- android:translationZ="8dp" />
+ android:padding="16dp"
+ android:translationZ="9dp" />
</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 33effba..2e92042 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -16,17 +16,18 @@
** limitations under the License.
*/
-->
-<LinearLayout
+<com.android.keyguard.AlphaOptimizedLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal">
<FrameLayout
android:layout_height="17dp"
- android:layout_width="wrap_content">
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/mobile_in"
android:layout_height="wrap_content"
@@ -44,9 +45,16 @@
android:visibility="gone"
/>
</FrameLayout>
+ <ImageView
+ android:id="@+id/mobile_type"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:visibility="gone" />
<FrameLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical">
<com.android.systemui.statusbar.AnimatedImageView
android:theme="@style/DualToneLightTheme"
android:id="@+id/mobile_signal"
@@ -63,11 +71,6 @@
systemui:hasOverlappingRendering="false"
/>
<ImageView
- android:id="@+id/mobile_type"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- />
- <ImageView
android:id="@+id/mobile_roaming"
android:layout_width="wrap_content"
android:layout_height="17dp"
@@ -76,7 +79,7 @@
android:paddingBottom="3dp"
android:scaleType="fitCenter"
android:src="@drawable/stat_sys_roaming"
- android:contentDescription="@string/accessibility_data_connection_roaming"
+ android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
</FrameLayout>
-</LinearLayout>
+</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 759d1ed..b1cb6cf 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -29,6 +29,7 @@
<!-- Package Info -->
<RelativeLayout
+ android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
@@ -140,6 +141,12 @@
android:layout_height="match_parent"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
+ android:id="@+id/minimize"
+ android:text="@string/inline_minimize_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ style="@style/TextAppearance.NotificationInfo.Button" />
+ <TextView
android:id="@+id/keep"
android:text="@string/inline_keep_button"
android:layout_width="wrap_content"
@@ -157,10 +164,11 @@
android:visibility="gone"
android:orientation="horizontal" >
<TextView
+ android:id="@+id/confirmation_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_channel_disabled"
- style="@style/TextAppearance.NotificationInfo.Secondary.Warning"/>
+ style="@style/TextAppearance.NotificationInfo.Confirmation"/>
<TextView
android:id="@+id/undo"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 9bf7870..7500bc6 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -43,6 +43,14 @@
android:layout_gravity="center_vertical"
android:gravity="end" >
+ <include
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:layout_margin="15dp"
+ android:visibility="gone"
+ layout="@layout/mobile_signal_group" />
+
<com.android.keyguard.CarrierText
android:id="@+id/qs_carrier_text"
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 89d6e99..7ec437c 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -29,7 +29,7 @@
android:alpha="0"
android:text="@string/quick_settings_header_onboarding_text"
android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/colorAccent"
+ android:textColor="?android:attr/textColorSecondary"
android:visibility="invisible" />
<LinearLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index b6d241b..0063f6a 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.volume.VolumeUiLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -89,4 +89,4 @@
</LinearLayout>
</LinearLayout>
-</com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-h650dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
similarity index 75%
copy from packages/SystemUI/res/values-h650dp/dimens.xml
copy to packages/SystemUI/res/values-h800dp/dimens.xml
index 8a00953..6a0e880 100644
--- a/packages/SystemUI/res/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2014 The Android Open Source Project
+ ~ Copyright (C) 2018 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.
@@ -15,5 +15,6 @@
-->
<resources>
- <dimen name="keyguard_clock_notifications_margin">32dp</dimen>
+ <!-- Minimum margin between clock and top of screen or ambient indication -->
+ <dimen name="keyguard_clock_top_margin">76dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e2a94df..5b038b1 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -160,12 +160,12 @@
<color name="smart_reply_button_background">#fff2f2f2</color>
<!-- Fingerprint dialog colors -->
- <color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white -->
- <color name="fingerprint_dialog_text_dark_color">#ff212121</color>
- <color name="fingerprint_dialog_text_light_color">#ff757575</color>
+ <color name="fingerprint_dialog_bg_color">#ffffffff</color> <!-- 100% white -->
+ <color name="fingerprint_dialog_text_dark_color">#dd000000</color> <!-- 87% black -->
+ <color name="fingerprint_dialog_text_light_color">#89000000</color> <!-- 54% black -->
<color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
- <color name="fingerprint_dialog_error_message_color">#ffff5722</color>
- <color name="fingerprint_dialog_fingerprint_color">#ff009688</color>
+ <color name="fingerprint_dialog_error_message_color">#ffd93025</color> <!-- google red 600 -->
+ <color name="fingerprint_dialog_fingerprint_color">#ff008577</color> <!-- google blue 600 -->
<!-- Logout button -->
<color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7b1a9e1..52b053b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -443,8 +443,8 @@
<!-- The margin between the clock and the notifications on Keyguard.-->
<dimen name="keyguard_clock_notifications_margin">30dp</dimen>
- <!-- Minimum margin between clock and top of screen or ambient indication -->
- <dimen name="keyguard_clock_top_margin">26dp</dimen>
+ <!-- Minimum margin between clock and status bar -->
+ <dimen name="keyguard_clock_top_margin">36dp</dimen>
<dimen name="heads_up_scrim_height">250dp</dimen>
<item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
@@ -882,7 +882,7 @@
burn-in on AOD -->
<dimen name="burn_in_prevention_offset_y">50dp</dimen>
- <dimen name="corner_size">16dp</dimen>
+ <dimen name="corner_size">8dp</dimen>
<dimen name="top_padding">0dp</dimen>
<dimen name="bottom_padding">48dp</dimen>
<dimen name="edge_margin">16dp</dimen>
@@ -906,8 +906,9 @@
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
<!-- Fingerprint Dialog values -->
- <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
+ <dimen name="fingerprint_dialog_fp_icon_size">64dp</dimen>
<dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
+ <dimen name="fingerprint_dialog_corner_size">2dp</dimen>
<!-- Wireless Charging Animation values -->
<dimen name="wireless_charging_dots_radius_start">0dp</dimen>
diff --git a/packages/SystemUI/res/values-h650dp/dimens.xml b/packages/SystemUI/res/values/integers.xml
similarity index 76%
rename from packages/SystemUI/res/values-h650dp/dimens.xml
rename to packages/SystemUI/res/values/integers.xml
index 8a00953..8f23283 100644
--- a/packages/SystemUI/res/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2014 The Android Open Source Project
+ ~ Copyright (C) 2018 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.
@@ -13,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
<resources>
- <dimen name="keyguard_clock_notifications_margin">32dp</dimen>
+ <integer name="fingerprint_dialog_text_gravity">8388611</integer> <!-- gravity start -->
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c89d818..b7c1c55 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -362,41 +362,41 @@
<!-- Content description of an item that is connecting for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_connecting">Connecting.</string>
- <!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_gprs">GPRS</string>
+ <!-- Content description of the data connection type GPRS. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_gprs">GPRS</string>
- <!-- Content description of the data connection type 1x for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_1x">1 X</string>
+ <!-- Content description of the data connection type 1x. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_1x">1 X</string>
- <!-- Content description of the data connection type HSPA and its variants for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_hspa">HSPA</string>
+ <!-- Content description of the data connection type HSPA and its variants. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_hspa">HSPA</string>
- <!-- Content description of the data connection type 3G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_3g">3G</string>
+ <!-- Content description of the data connection type 3G. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_3g">3G</string>
- <!-- Content description of the data connection type 3.5G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_3.5g">3.5G</string>
+ <!-- Content description of the data connection type 3.5G. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_3_5g">3.5G</string>
- <!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_4g">4G</string>
+ <!-- Content description of the data connection type 4G . [CHAR LIMIT=NONE] -->
+ <string name="data_connection_4g">4G</string>
- <!-- Content description of the data connection type 4G for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_4g_plus">4G+</string>
+ <!-- Content description of the data connection type 4G+. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_4g_plus">4G+</string>
- <!-- Content description of the data connection type LTE for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_lte">LTE</string>
+ <!-- Content description of the data connection type LTE. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_lte">LTE</string>
- <!-- Content description of the data connection type LTE+ for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_lte_plus">LTE+</string>
+ <!-- Content description of the data connection type LTE+. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_lte_plus">LTE+</string>
- <!-- Content description of the data connection type CDMA for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_cdma">CDMA</string>
+ <!-- Content description of the data connection type CDMA. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_cdma">CDMA</string>
- <!-- Content description of the roaming data connection type for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_roaming">Roaming</string>
+ <!-- Content description of the roaming data connection type. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_roaming">Roaming</string>
- <!-- Content description of the data connection type Edge for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_edge">Edge</string>
+ <!-- Content description of the data connection type Edge. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_edge">EDGE</string>
<!-- Content description of the data connection type WiFi for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_data_connection_wifi">Wi-Fi</string>
@@ -411,7 +411,7 @@
<string name="accessibility_cell_data_on">Mobile Data On</string>
<!-- Content description of the cell data being disabled. [CHAR LIMIT=NONE] -->
- <string name="accessibility_cell_data_off">Mobile Data Off</string>
+ <string name="cell_data_off">Mobile data off</string>
<!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_bluetooth_tether">Bluetooth tethering.</string>
@@ -425,8 +425,8 @@
<!-- Content description of the no sim icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_no_sims">No SIM card.</string>
- <!-- Content description of the carrier network changing icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_carrier_network_change_mode">Carrier network changing.</string>
+ <!-- Content description of the carrier network changing icon. [CHAR LIMIT=NONE] -->
+ <string name="carrier_network_change_mode">Carrier network changing</string>
<!-- Content description of button to open battery details icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_battery_details">Open battery details</string>
@@ -780,6 +780,9 @@
<string name="quick_settings_hotspot_label">Hotspot</string>
<!-- QuickSettings: Hotspot. Secondary label shown when the hotspot is being enabled [CHAR LIMIT=NONE] -->
<string name="quick_settings_hotspot_secondary_label_transient">Turning on…</string>
+ <!-- QuickSettings: Hotspot. Secondary label shown when Data Saver mode is enabled to explain to
+ the user why they can't toggle the hotspot tile. [CHAR LIMIT=20] -->
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled">Data Saver is on</string>
<!-- QuickSettings: Hotspot: Secondary label for how many devices are connected to the hotspot [CHAR LIMIT=NONE] -->
<plurals name="quick_settings_hotspot_secondary_label_num_devices">
<item quantity="one">%d device</item>
@@ -1526,6 +1529,9 @@
<!-- Notification Inline Controls: Shown when a channel's notifications are currently blocked -->
<string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
+ <!-- Notification inline controls: Shown when a channel's notifications are minimized -->
+ <string name="notification_channel_minimized">These notifications will be minimized</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_blocking_helper">You usually dismiss these notifications.
\nKeep showing them?</string>
@@ -1539,12 +1545,34 @@
<!-- Notification inline controls: keep getting notifications button -->
<string name="inline_keep_button">Keep showing</string>
+ <!-- Notification inline controls: minimize notifications button -->
+ <string name="inline_minimize_button">Minimize</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, app level -->
<string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
+ <string name="notification_appops_camera_active">camera</string>
+
+ <string name="notification_appops_microphone_active">microphone</string>
+
+ <string name="notification_appops_overlay_active">displaying over other apps on your screen</string>
+
+ <plurals name="notification_appops">
+ <item quantity="one">This app is <xliff:g id="performing activity" example="using the camera">%1$s</xliff:g>.</item>
+ <item quantity="other">This app is <xliff:g id="performing activity" example="using the camera">%1$s</xliff:g> and <xliff:g id="performing activity" example="using the microphone">%2$s</xliff:g>.</item>
+ </plurals>
+
+ <plurals name="notification_using">
+ <item quantity="one">using the <xliff:g id="performing activity" example="camera">%1$s</xliff:g></item>
+ <item quantity="other">using the <xliff:g id="performing activity" example="camera">%1$s</xliff:g> and <xliff:g id="performing activity" example="microphone">%2$s</xliff:g></item>
+ </plurals>
+
+ <string name="notification_appops_settings">Settings</string>
+ <string name="notification_appops_ok">Ok</string>
+
<!-- Notification: Control panel: Accessibility description for expanded inline controls view, used
to control settings about notifications related to the current notification. -->
<string name="notification_channel_controls_opened_accessibility">Notification controls for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> opened</string>
@@ -1922,8 +1950,8 @@
<!-- accessibility label for button to select user [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_user">Signed in as <xliff:g name="user" example="John">%s</xliff:g></string>
- <!-- accessibility label for no internet [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_no_internet">No internet.</string>
+ <!-- Content description for no internet connection [CHAR LIMIT=NONE] -->
+ <string name="data_connection_no_internet">No internet</string>
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_details">Open details.</string>
@@ -2077,6 +2105,9 @@
<!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
<string name="mobile_data">Mobile data</string>
+ <!-- Quick settings tile secondary label format combining roaming with the mobile data type. [CHAR LIMIT=NONE] -->
+ <string name="mobile_data_text_format"><xliff:g name="roaming_status" example="Roaming">%s</xliff:g> \u2014 <xliff:g name="mobile_data_type" example="LTE">%s</xliff:g></string>
+
<!-- Label for when wifi is off in QS detail panel [CHAR LIMIT=NONE] -->
<string name="wifi_is_off">Wi-Fi is off</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d006af1..1470dfa 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -335,6 +335,7 @@
<style name="qs_theme" parent="qs_base">
<item name="lightIconTheme">@style/QSIconTheme</item>
<item name="darkIconTheme">@style/QSIconTheme</item>
+ <item name="android:windowIsFloating">true</item>
</style>
<style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
@@ -345,7 +346,9 @@
<style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
- <style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen" />
+ <style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
+ <item name="android:windowIsFloating">true</item>
+ </style>
<style name="QSBorderlessButton">
<item name="android:padding">12dp</item>
@@ -456,6 +459,12 @@
<item name="android:alpha">0.87</item>
</style>
+ <style name="TextAppearance.NotificationInfo.Confirmation">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:alpha">0.87</item>
+ </style>
+
<style name="TextAppearance.NotificationInfo.Secondary">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">14sp</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index e200a7f..ef36610 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -65,4 +65,19 @@
* Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
*/
void onQuickScrubProgress(float progress);
+
+ /**
+ * Sent when overview button is pressed to toggle show/hide of overview.
+ */
+ void onOverviewToggle();
+
+ /**
+ * Sent when overview is to be shown.
+ */
+ void onOverviewShown(boolean triggeredFromAltTab);
+
+ /**
+ * Sent when overview is to be hidden.
+ */
+ void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index dd1763b..924e85d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -31,6 +31,7 @@
public int orientation;
public Rect insets;
public boolean reducedResolution;
+ public boolean isRealSnapshot;
public float scale;
public ThumbnailData() {
@@ -39,6 +40,7 @@
insets = new Rect();
reducedResolution = false;
scale = 1f;
+ isRealSnapshot = true;
}
public ThumbnailData(TaskSnapshot snapshot) {
@@ -47,5 +49,6 @@
orientation = snapshot.getOrientation();
reducedResolution = snapshot.isReducedResolution();
scale = snapshot.getScale();
+ isRealSnapshot = snapshot.isRealSnapshot();
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
new file mode 100644
index 0000000..0d5933e
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.shared.system;
+
+import android.content.Context;
+
+import com.android.internal.util.LatencyTracker;
+
+/**
+ * @see LatencyTracker
+ */
+public class LatencyTrackerCompat {
+ public static boolean isEnabled(Context context) {
+ return LatencyTracker.isEnabled(context);
+ }
+
+ public static void logToggleRecents(int duration) {
+ LatencyTracker.logAction(LatencyTracker.ACTION_TOGGLE_RECENTS, duration);
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 17191868..b8193a89 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -22,12 +22,13 @@
public class NavigationBarCompat {
@Retention(RetentionPolicy.SOURCE)
- @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME})
+ @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW})
public @interface HitTarget{}
public static final int HIT_TARGET_NONE = 0;
public static final int HIT_TARGET_BACK = 1;
public static final int HIT_TARGET_HOME = 2;
+ public static final int HIT_TARGET_OVERVIEW = 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef({FLAG_DISABLE_SWIPE_UP,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index b8c5049..0f52209 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -18,7 +18,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import android.app.WindowConfiguration;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.RemoteAnimationTarget;
@@ -39,6 +38,7 @@
public final int prefixOrderIndex;
public final Point position;
public final Rect sourceContainerBounds;
+ public final boolean isNotInRecents;
private final RemoteAnimationTarget mTarget;
@@ -52,6 +52,7 @@
position = app.position;
sourceContainerBounds = app.sourceContainerBounds;
prefixOrderIndex = app.prefixOrderIndex;
+ isNotInRecents = app.isNotInRecents;
}
public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index 45d1aad8..5b0f1c3 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -39,9 +39,15 @@
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
+
import android.telephony.TelephonyManager;
public class CarrierText extends TextView {
+ /** Do not show missing sim message. */
+ public static final int FLAG_HIDE_MISSING_SIM = 1 << 0;
+ /** Do not show airplane mode message. */
+ public static final int FLAG_HIDE_AIRPLANE_MODE = 1 << 1;
+
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final String TAG = "CarrierText";
@@ -55,6 +61,8 @@
private boolean[] mSimErrorState = new boolean[TelephonyManager.getDefault().getPhoneCount()];
+ private int mFlags;
+
private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshCarrierInfo() {
@@ -85,6 +93,11 @@
}
};
};
+
+ public void setDisplayFlags(int flags) {
+ mFlags = flags;
+ }
+
/**
* The status of this lock screen. Primarily used for widgets on LockScreen.
*/
@@ -196,8 +209,7 @@
// Grab the first subscripton, because they all should contain the emergency text,
// described above.
displayText = makeCarrierStringOnEmergencyCapable(
- getContext().getText(R.string.keyguard_missing_sim_message_short),
- subs.get(0).getCarrierName());
+ getMissingSimMessage(), subs.get(0).getCarrierName());
} else {
// We don't have a SubscriptionInfo to get the emergency calls only from.
// Grab it from the old sticky broadcast if possible instead. We can use it
@@ -223,8 +235,7 @@
text = concatenate(plmn, spn);
}
}
- displayText = makeCarrierStringOnEmergencyCapable(
- getContext().getText(R.string.keyguard_missing_sim_message_short), text);
+ displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
}
}
@@ -232,11 +243,21 @@
// APM (airplane mode) != no carrier state. There are carrier services
// (e.g. WFC = Wi-Fi calling) which may operate in APM.
if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
- displayText = getContext().getString(R.string.airplane_mode);
+ displayText = getAirplaneModeMessage();
}
setText(displayText);
}
+ private String getMissingSimMessage() {
+ return (mFlags & FLAG_HIDE_MISSING_SIM) == 0
+ ? getContext().getString(R.string.keyguard_missing_sim_message_short) : "";
+ }
+
+ private String getAirplaneModeMessage() {
+ return (mFlags & FLAG_HIDE_AIRPLANE_MODE) == 0
+ ? getContext().getString(R.string.airplane_mode) : "";
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 474fc90..62b5004 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -149,7 +149,6 @@
mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
mSecurityContainer.setSecurityCallback(this);
mSecurityContainer.showPrimarySecurityScreen(false);
- // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 6b99206..f0952f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -331,6 +331,37 @@
updateVisibility();
}
+ public static class Row extends LinearLayout {
+
+ public Row(Context context) {
+ super(context);
+ }
+
+ public Row(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public Row(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public Row(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof KeyguardSliceButton) {
+ ((KeyguardSliceButton) child).setMaxWidth(width / 2);
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
/**
* Representation of an item that appears under the clock on main keyguard message.
*/
@@ -344,7 +375,6 @@
setPadding(horizontalPadding / 2, 0, horizontalPadding / 2, 0);
setCompoundDrawablePadding((int) context.getResources()
.getDimension(R.dimen.widget_icon_padding));
- setMaxWidth(KeyguardSliceView.this.getWidth() / 2);
setMaxLines(1);
setEllipsize(TruncateAt.END);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a3ffa40..8a4f324 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -20,6 +20,7 @@
import android.app.AlarmManager;
import android.app.IActivityManager;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
@@ -357,7 +358,7 @@
updateDozeVisibleViews();
mKeyguardSlice.setDark(darkAmount);
mClockView.setTextColor(blendedTextColor);
- mClockSeparator.setBackgroundColor(blendedTextColor);
+ mClockSeparator.setBackgroundTintList(ColorStateList.valueOf(blendedTextColor));
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
index 467ec2e..fb2eb4c 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
@@ -61,7 +61,7 @@
: R.drawable.rounded_bg_bottom).mutate(),
};
}
- layers[1].setTint(Utils.getColorAttr(context, android.R.attr.colorPrimaryDark));
+ layers[1].setTint(Utils.getColorAttr(context, android.R.attr.colorPrimary));
return layers;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index 526e5fa..e18ac74 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -79,8 +79,8 @@
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
Data data = mStrokeMap.get(stroke);
- return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
- + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
+ return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance(), type)
+ + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage(), type);
}
private static class Data {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
index e6c42da..e6e42f2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
@@ -17,10 +17,11 @@
package com.android.systemui.classifier;
public class AnglesPercentageEvaluator {
- public static float evaluate(float value) {
+ public static float evaluate(float value, int type) {
+ final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
- if (value < 1.00) evaluation++;
- if (value < 0.90) evaluation++;
+ if (value < 1.00 && !secureUnlock) evaluation++;
+ if (value < 0.90 && !secureUnlock) evaluation++;
if (value < 0.70) evaluation++;
return evaluation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
index 99cc1a6..6883dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -17,14 +17,15 @@
package com.android.systemui.classifier;
public class AnglesVarianceEvaluator {
- public static float evaluate(float value) {
+ public static float evaluate(float value, int type) {
+ final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
if (value > 0.05) evaluation++;
if (value > 0.10) evaluation++;
if (value > 0.20) evaluation++;
- if (value > 0.40) evaluation++;
- if (value > 0.80) evaluation++;
- if (value > 1.50) evaluation++;
+ if (value > 0.40 && !secureUnlock) evaluation++;
+ if (value > 0.80 && !secureUnlock) evaluation++;
+ if (value > 1.50 && !secureUnlock) evaluation++;
return evaluation;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index cb761a9..909896e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -31,6 +31,7 @@
public static final int LEFT_AFFORDANCE = 5;
public static final int RIGHT_AFFORDANCE = 6;
public static final int GENERIC = 7;
+ public static final int BOUNCER_UNLOCK = 8;
/**
* Contains all the information about touch events from which the classifier can query
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
index e20b1ca6..5f04222 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
@@ -33,6 +33,7 @@
}
break;
case Classifier.UNLOCK:
+ case Classifier.BOUNCER_UNLOCK:
if (!vertical || yDiff >= 0.0) {
return falsingEvaluation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index ed659e2..913e781 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -356,11 +356,12 @@
mDataCollector.setQsExpanded(expanded);
}
- public void onTrackingStarted() {
+ public void onTrackingStarted(boolean secure) {
if (FalsingLog.ENABLED) {
FalsingLog.i("onTrackingStarted", "");
}
- mHumanInteractionClassifier.setType(Classifier.UNLOCK);
+ mHumanInteractionClassifier.setType(secure ?
+ Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
mDataCollector.onTrackingStarted();
}
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 1d43b1d..4b15fbc 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -180,8 +180,8 @@
}
}
mReceiver = null;
- mWindowManager.removeView(mDialogView);
mDialogShowing = false;
+ mDialogView.startDismiss();
}
private void handleButtonNegative() {
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index e828b2c..37e1936 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -61,7 +61,7 @@
private final IBinder mWindowToken = new Binder();
private final Interpolator mLinearOutSlowIn;
- private final Interpolator mFastOutLinearIn;
+ private final WindowManager mWindowManager;
private final float mAnimationTranslationOffset;
private final int mErrorTextColor;
private final int mTextColor;
@@ -78,7 +78,7 @@
super(context);
mHandler = handler;
mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
- mFastOutLinearIn = Interpolators.FAST_OUT_LINEAR_IN;
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mAnimationTranslationOffset = getResources()
.getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
mErrorTextColor = Color.parseColor(
@@ -189,6 +189,34 @@
});
}
+ public void startDismiss() {
+ final Runnable endActionRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mWindowManager.removeView(FingerprintDialogView.this);
+ }
+ };
+
+ postOnAnimation(new Runnable() {
+ @Override
+ public void run() {
+ mLayout.animate()
+ .alpha(0f)
+ .setDuration(ANIMATION_DURATION)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .start();
+ mDialog.animate()
+ .translationY(mAnimationTranslationOffset)
+ .setDuration(ANIMATION_DURATION)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .withEndAction(endActionRunnable)
+ .start();
+ }
+ });
+ }
+
public void setBundle(Bundle bundle) {
mBundle = bundle;
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index c4c1ba7..e171b53 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -14,6 +14,7 @@
package com.android.systemui.globalactions;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
@@ -877,9 +878,8 @@
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
- // Power off, restart, logout (if present) and lockdown (if present) should be in white
- // background. Set the division based on which buttons are currently being displayed.
- if (position == 2 + (mHasLogoutButton ? 1 : 0) + (mHasLockdownButton ? 1 : 0)) {
+ // Everything but screenshot, the last item, gets white background.
+ if (position == getCount() - 1) {
HardwareUiLayout.get(parent).setDivisionView(view);
}
return view;
@@ -1357,11 +1357,17 @@
// Window initialization
Window window = getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+ // Inflate the decor view, so the attributes below are not overwritten by the theme.
+ window.getDecorView();
+ window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ window.setLayout(MATCH_PARENT, MATCH_PARENT);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.addFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 3563437..a1adfa6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -15,12 +15,14 @@
package com.android.systemui.globalactions;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import android.app.Dialog;
import android.app.KeyguardManager;
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Point;
+import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
@@ -80,15 +82,21 @@
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
// Window initialization
Window window = d.getWindow();
+ window.requestFeature(Window.FEATURE_NO_TITLE);
+ window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ // Inflate the decor view, so the attributes below are not overwritten by the theme.
+ window.getDecorView();
window.getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
+ window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- window.requestFeature(Window.FEATURE_NO_TITLE);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.addFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6940264..a1b17e4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -83,6 +83,7 @@
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -2011,8 +2012,9 @@
}
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
- ViewGroup container, FingerprintUnlockController fingerprintUnlockController) {
- mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
+ ViewGroup container, NotificationPanelView panelView,
+ FingerprintUnlockController fingerprintUnlockController) {
+ mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
fingerprintUnlockController, mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index e9888df..dbf1745 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
@@ -27,6 +28,7 @@
import android.os.UserManager;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
@@ -36,15 +38,18 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.keyguard.CarrierText;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.R.dimen;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
@@ -64,7 +69,7 @@
private UserInfoController mUserInfoController;
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
- private View mCarrierText;
+ private CarrierText mCarrierText;
private boolean mQsDisabled;
private QSPanel mQsPanel;
@@ -86,9 +91,15 @@
private View mActionsContainer;
private View mDragHandle;
+ private View mMobileGroup;
+ private ImageView mMobileSignal;
+ private ImageView mMobileRoaming;
+ private final int mColorForeground;
+ private final CellSignalState mInfo = new CellSignalState();
public QSFooterImpl(Context context, AttributeSet attrs) {
super(context, attrs);
+ mColorForeground = Utils.getColorAttr(context, android.R.attr.colorForeground);
}
@Override
@@ -104,7 +115,12 @@
mSettingsContainer = findViewById(R.id.settings_button_container);
mSettingsButton.setOnClickListener(this);
+ mMobileGroup = findViewById(R.id.mobile_combo);
+ mMobileSignal = findViewById(R.id.mobile_signal);
+ mMobileRoaming = findViewById(R.id.mobile_roaming);
mCarrierText = findViewById(R.id.qs_carrier_text);
+ mCarrierText.setDisplayFlags(
+ CarrierText.FLAG_HIDE_AIRPLANE_MODE | CarrierText.FLAG_HIDE_MISSING_SIM);
mMultiUserSwitch = findViewById(R.id.multi_user_switch);
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
@@ -165,6 +181,7 @@
return new TouchAnimator.Builder()
.addFloat(mDivider, "alpha", 0, 1)
.addFloat(mCarrierText, "alpha", 0, 0, 1)
+ .addFloat(mMobileGroup, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
.addFloat(mDragHandle, "alpha", 1, 0, 0)
.setStartDelay(0.15f)
@@ -338,4 +355,64 @@
}
mMultiUserAvatar.setImageDrawable(picture);
}
+
+ private void handleUpdateState() {
+ mMobileGroup.setVisibility(mInfo.visible ? View.VISIBLE : View.GONE);
+ if (mInfo.visible) {
+ mMobileRoaming.setVisibility(mInfo.roaming ? View.VISIBLE : View.GONE);
+ mMobileRoaming.setImageTintList(ColorStateList.valueOf(mColorForeground));
+ SignalDrawable d = new SignalDrawable(mContext);
+ d.setDarkIntensity(QuickStatusBarHeader.getColorIntensity(mColorForeground));
+ mMobileSignal.setImageDrawable(d);
+ mMobileSignal.setImageLevel(mInfo.mobileSignalIconId);
+
+ StringBuilder contentDescription = new StringBuilder();
+ if (mInfo.contentDescription != null) {
+ contentDescription.append(mInfo.contentDescription).append(", ");
+ }
+ if (mInfo.roaming) {
+ contentDescription
+ .append(mContext.getString(R.string.data_connection_roaming))
+ .append(", ");
+ }
+ // TODO: show mobile data off/no internet text for 5 seconds before carrier text
+ if (TextUtils.equals(mInfo.typeContentDescription,
+ mContext.getString(R.string.data_connection_no_internet))
+ || TextUtils.equals(mInfo.typeContentDescription,
+ mContext.getString(R.string.cell_data_off))) {
+ contentDescription.append(mInfo.typeContentDescription);
+ }
+ mMobileSignal.setContentDescription(contentDescription);
+ }
+ }
+
+ @Override
+ public void setMobileDataIndicators(NetworkController.IconState statusIcon,
+ NetworkController.IconState qsIcon, int statusType,
+ int qsType, boolean activityIn, boolean activityOut,
+ String typeContentDescription,
+ String description, boolean isWide, int subId, boolean roaming) {
+ mInfo.visible = statusIcon.visible;
+ mInfo.mobileSignalIconId = statusIcon.icon;
+ mInfo.contentDescription = statusIcon.contentDescription;
+ mInfo.typeContentDescription = typeContentDescription;
+ mInfo.roaming = roaming;
+ handleUpdateState();
+ }
+
+ @Override
+ public void setNoSims(boolean hasNoSims, boolean simDetected) {
+ if (hasNoSims) {
+ mInfo.visible = false;
+ }
+ handleUpdateState();
+ }
+
+ private final class CellSignalState {
+ boolean visible;
+ int mobileSignalIconId;
+ public String contentDescription;
+ String typeContentDescription;
+ boolean roaming;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 2151436..a48dcc6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.annotation.ColorInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
@@ -31,6 +32,7 @@
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -60,12 +62,14 @@
*/
public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
+ private static final String TAG = "QuickStatusBarHeader";
+ private static final boolean DEBUG = false;
/** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
private static final int FADE_ANIMATION_DURATION_MS = 300;
private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
- public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
+ public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
private final Handler mHandler = new Handler();
@@ -128,7 +132,7 @@
Rect tintArea = new Rect(0, 0, 0, 0);
int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
- float intensity = colorForeground == Color.WHITE ? 0 : 1;
+ float intensity = getColorIntensity(colorForeground);
int fillColor = fillColorForIntensity(intensity, getContext());
// Set light text on the header icons because they will always be on a black background
@@ -292,6 +296,7 @@
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null;
+
if (mNextAlarmText != null) {
hideLongPressTooltip(true /* shouldFadeInAlarmText */);
} else {
@@ -351,6 +356,7 @@
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
mLongPressTooltipView.setVisibility(View.INVISIBLE);
if (shouldShowAlarmText) {
@@ -361,7 +367,6 @@
.start();
} else {
mLongPressTooltipView.setVisibility(View.INVISIBLE);
-
if (shouldShowAlarmText) {
showAlarmText();
}
@@ -377,9 +382,11 @@
mNextAlarmView.setVisibility(View.VISIBLE);
mNextAlarmTextView.setText(mNextAlarmText);
+ // Animate the alarm back in. Make sure to clear the animator listener for the animation!
mNextAlarmView.animate()
.alpha(1f)
.setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(null)
.start();
}
@@ -394,6 +401,8 @@
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text");
+
// Reset the alpha regardless of how the animation ends for the next
// time we show this view/want to animate it.
mNextAlarmView.setVisibility(View.INVISIBLE);
@@ -443,4 +452,9 @@
.getBestDateTimePattern(Locale.getDefault(), skeleton);
return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
}
+
+ public static float getColorIntensity(@ColorInt int color) {
+ return color == Color.WHITE ? 0 : 1;
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 66823ca..1cb89c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -92,9 +92,10 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int numTiles = mRecords.size();
final int width = MeasureSpec.getSize(widthMeasureSpec);
- final int rows = (numTiles + mColumns - 1) / mColumns;
+ final int numRows = (numTiles + mColumns - 1) / mColumns;
mCellWidth = (width - (mCellMarginHorizontal * (mColumns + 1))) / mColumns;
+ // Measure each QS tile.
View previousView = this;
for (TileRecord record : mRecords) {
if (record.tileView.getVisibility() == GONE) continue;
@@ -104,9 +105,10 @@
// Only include the top margin in our measurement if we have more than 1 row to show.
// Otherwise, don't add the extra margin buffer at top.
- int height = (mCellHeight + mCellMarginVertical) * rows +
- (rows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
+ int height = (mCellHeight + mCellMarginVertical) * numRows +
+ (numRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
if (height < 0) height = 0;
+
setMeasuredDimension(width, height);
}
@@ -122,24 +124,30 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int w = getWidth();
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
int row = 0;
int column = 0;
+
+ // Layout each QS tile.
for (int i = 0; i < mRecords.size(); i++, column++) {
+ // If we reached the last column available to layout a tile, wrap back to the next row.
if (column == mColumns) {
+ column = 0;
row++;
- column -= mColumns;
}
- TileRecord record = mRecords.get(i);
- int left = getColumnStart(column);
+
+ final TileRecord record = mRecords.get(i);
final int top = getRowTop(row);
- int right;
+ final int right;
+ final int left;
if (isRtl) {
- right = w - left;
+ right = w - getColumnStart(column);
left = right - mCellWidth;
} else {
+ left = getColumnStart(column);
right = left + mCellWidth;
}
+
record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 95504ed..89f86c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -129,6 +129,7 @@
super.setBatteryLevel(MAX_BATTERY);
setPowerSave(true);
setCharging(false);
+ setPowerSaveAsColorError(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 0ce3e6a..b7a64e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -18,18 +18,18 @@
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.os.SystemProperties;
+import android.provider.Settings;
import android.service.quicksettings.Tile;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.widget.Switch;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.net.DataUsageController;
@@ -41,7 +41,6 @@
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.qs.CellTileView;
-import com.android.systemui.qs.CellTileView.SignalIcon;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -52,16 +51,6 @@
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTileImpl<SignalState> {
- private static final ComponentName CELLULAR_SETTING_COMPONENT = new ComponentName(
- "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity");
- private static final ComponentName DATA_PLAN_CELLULAR_COMPONENT = new ComponentName(
- "com.android.settings", "com.android.settings.Settings$DataPlanUsageSummaryActivity");
-
- private static final Intent CELLULAR_SETTINGS =
- new Intent().setComponent(CELLULAR_SETTING_COMPONENT);
- private static final Intent DATA_PLAN_CELLULAR_SETTINGS =
- new Intent().setComponent(DATA_PLAN_CELLULAR_COMPONENT);
-
private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan";
private final NetworkController mController;
@@ -107,7 +96,7 @@
@Override
public Intent getLongClickIntent() {
- return getCellularSettingIntent(mContext);
+ return getCellularSettingIntent();
}
@Override
@@ -148,8 +137,7 @@
showDetail(true);
} else {
mActivityStarter
- .postStartActivityDismissingKeyguard(getCellularSettingIntent(mContext),
- 0 /* delay */);
+ .postStartActivityDismissingKeyguard(getCellularSettingIntent(),0 /* delay */);
}
}
@@ -168,35 +156,43 @@
final Resources r = mContext.getResources();
state.activityIn = cb.enabled && cb.activityIn;
state.activityOut = cb.enabled && cb.activityOut;
- state.isOverlayIconWide = cb.isDataTypeIconWide;
- state.overlayIconId = cb.dataTypeIconId;
-
state.label = r.getString(R.string.mobile_data);
-
- final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
- ? cb.signalContentDescription
- : r.getString(R.string.accessibility_no_signal);
- if (cb.noSim) {
- state.contentDescription = state.label;
- } else {
- state.contentDescription = signalContentDesc + ", " + state.label;
- }
-
- state.expandedAccessibilityClassName = Switch.class.getName();
- state.value = mDataController.isMobileDataSupported()
+ boolean mobileDataEnabled = mDataController.isMobileDataSupported()
&& mDataController.isMobileDataEnabled();
-
+ state.value = mobileDataEnabled;
+ state.expandedAccessibilityClassName = Switch.class.getName();
if (cb.noSim) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim);
} else {
- state.icon = new SignalIcon(cb.mobileSignalIconId);
+ state.icon = ResourceIcon.get(R.drawable.ic_swap_vert);
}
- if (cb.airplaneModeEnabled | cb.noSim) {
+ if (cb.noSim) {
state.state = Tile.STATE_UNAVAILABLE;
- } else {
+ state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short);
+ } else if (cb.airplaneModeEnabled) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = r.getString(R.string.status_bar_airplane);
+ } else if (mobileDataEnabled) {
state.state = Tile.STATE_ACTIVE;
+ state.secondaryLabel = getMobileDataDescription(cb);
+ } else {
+ state.state = Tile.STATE_INACTIVE;
+ state.secondaryLabel = r.getString(R.string.cell_data_off);
}
+ state.contentDescription = state.label + ", " + state.secondaryLabel;
+ }
+
+ private CharSequence getMobileDataDescription(CallbackInfo cb) {
+ if (cb.roaming && !TextUtils.isEmpty(cb.dataContentDescription)) {
+ String roaming = mContext.getString(R.string.data_connection_roaming);
+ String dataDescription = cb.dataContentDescription;
+ return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription);
+ }
+ if (cb.roaming) {
+ return mContext.getString(R.string.data_connection_roaming);
+ }
+ return cb.dataContentDescription;
}
@Override
@@ -209,40 +205,18 @@
return mController.hasMobileDataFeature();
}
- // Remove the period from the network name
- public static String removeTrailingPeriod(String string) {
- if (string == null) return null;
- final int length = string.length();
- if (string.endsWith(".")) {
- return string.substring(0, length - 1);
- }
- return string;
- }
-
private static final class CallbackInfo {
boolean enabled;
- boolean wifiEnabled;
boolean airplaneModeEnabled;
- int mobileSignalIconId;
- String signalContentDescription;
- int dataTypeIconId;
String dataContentDescription;
boolean activityIn;
boolean activityOut;
- String enabledDesc;
boolean noSim;
- boolean isDataTypeIconWide;
boolean roaming;
}
private final class CellSignalCallback implements SignalCallback {
private final CallbackInfo mInfo = new CallbackInfo();
- @Override
- public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description, boolean isTransient) {
- mInfo.wifiEnabled = enabled;
- refreshState(mInfo);
- }
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
@@ -253,14 +227,9 @@
return;
}
mInfo.enabled = qsIcon.visible;
- mInfo.mobileSignalIconId = qsIcon.icon;
- mInfo.signalContentDescription = qsIcon.contentDescription;
- mInfo.dataTypeIconId = qsType;
mInfo.dataContentDescription = typeContentDescription;
mInfo.activityIn = activityIn;
mInfo.activityOut = activityOut;
- mInfo.enabledDesc = description;
- mInfo.isDataTypeIconWide = qsType != 0 && isWide;
mInfo.roaming = roaming;
refreshState(mInfo);
}
@@ -268,16 +237,6 @@
@Override
public void setNoSims(boolean show, boolean simDetected) {
mInfo.noSim = show;
- if (mInfo.noSim) {
- // Make sure signal gets cleared out when no sims.
- mInfo.mobileSignalIconId = 0;
- mInfo.dataTypeIconId = 0;
- // Show a No SIMs description to avoid emergency calls message.
- mInfo.enabled = true;
- mInfo.enabledDesc = mContext.getString(
- R.string.keyguard_missing_sim_message_short);
- mInfo.signalContentDescription = mInfo.enabledDesc;
- }
refreshState(mInfo);
}
@@ -293,25 +252,8 @@
}
}
- static Intent getCellularSettingIntent(Context context) {
- // TODO(b/62349208): We should replace feature flag check below with data plans
- // availability check. If the data plans are available we display the data plans usage
- // summary otherwise we display data usage summary without data plans.
- boolean isDataPlanFeatureEnabled =
- SystemProperties.getBoolean(ENABLE_SETTINGS_DATA_PLAN, false /* default */);
- context.getPackageManager()
- .setComponentEnabledSetting(
- DATA_PLAN_CELLULAR_COMPONENT,
- isDataPlanFeatureEnabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- context.getPackageManager()
- .setComponentEnabledSetting(
- CELLULAR_SETTING_COMPONENT,
- isDataPlanFeatureEnabled ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- : PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- return isDataPlanFeatureEnabled ? DATA_PLAN_CELLULAR_SETTINGS : CELLULAR_SETTINGS;
+ static Intent getCellularSettingIntent() {
+ return new Intent(Settings.ACTION_DATA_USAGE_SETTINGS);
}
private final class CellularDetailAdapter implements DetailAdapter {
@@ -330,7 +272,7 @@
@Override
public Intent getSettingsIntent() {
- return getCellularSettingIntent(mContext);
+ return getCellularSettingIntent();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index a102696..ace361b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -55,7 +55,7 @@
@Override
public Intent getLongClickIntent() {
- return CellularTile.getCellularSettingIntent(mContext);
+ return CellularTile.getCellularSettingIntent();
}
@Override
protected void handleClick() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index d675f5e..00d6bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.UserManager;
import android.provider.Settings.Global;
import android.service.quicksettings.Tile;
@@ -32,24 +31,27 @@
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTileImpl<AirplaneBooleanState> {
- static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
+ private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
"com.android.settings", "com.android.settings.TetherSettings"));
private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot);
- private final Icon mUnavailable = ResourceIcon.get(R.drawable.ic_hotspot_unavailable);
- private final HotspotController mController;
- private final Callback mCallback = new Callback();
+ private final HotspotController mHotspotController;
+ private final DataSaverController mDataSaverController;
+
+ private final HotspotAndDataSaverCallbacks mCallbacks = new HotspotAndDataSaverCallbacks();
private final GlobalSetting mAirplaneMode;
private boolean mListening;
public HotspotTile(QSHost host) {
super(host);
- mController = Dependency.get(HotspotController.class);
+ mHotspotController = Dependency.get(HotspotController.class);
+ mDataSaverController = Dependency.get(DataSaverController.class);
mAirplaneMode = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
@Override
protected void handleValueChanged(int value) {
@@ -60,7 +62,7 @@
@Override
public boolean isAvailable() {
- return mController.isHotspotSupported();
+ return mHotspotController.isHotspotSupported();
}
@Override
@@ -78,12 +80,12 @@
if (mListening == listening) return;
mListening = listening;
if (listening) {
- mController.addCallback(mCallback);
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mHotspotController.addCallback(mCallbacks);
+ mDataSaverController.addCallback(mCallbacks);
refreshState();
} else {
- mController.removeCallback(mCallback);
+ mHotspotController.removeCallback(mCallbacks);
+ mDataSaverController.removeCallback(mCallbacks);
}
mAirplaneMode.setListening(listening);
}
@@ -101,7 +103,7 @@
}
// Immediately enter transient enabling state when turning hotspot on.
refreshState(isEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
- mController.setHotspotEnabled(!isEnabled);
+ mHotspotController.setHotspotEnabled(!isEnabled);
}
@Override
@@ -117,21 +119,24 @@
}
final int numConnectedDevices;
- final boolean isTransient = transientEnabling || mController.isHotspotTransient();
+ final boolean isTransient = transientEnabling || mHotspotController.isHotspotTransient();
+ final boolean isDataSaverEnabled;
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
+
if (arg instanceof CallbackInfo) {
- CallbackInfo info = (CallbackInfo) arg;
- state.value = info.enabled;
+ final CallbackInfo info = (CallbackInfo) arg;
+ state.value = transientEnabling || info.isHotspotEnabled;
numConnectedDevices = info.numConnectedDevices;
+ isDataSaverEnabled = info.isDataSaverEnabled;
} else {
- state.value = transientEnabling || mController.isHotspotEnabled();
- numConnectedDevices = mController.getNumConnectedDevices();
+ state.value = transientEnabling || mHotspotController.isHotspotEnabled();
+ numConnectedDevices = mHotspotController.getNumConnectedDevices();
+ isDataSaverEnabled = mDataSaverController.isDataSaverEnabled();
}
state.icon = mEnabledStatic;
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
- state.secondaryLabel = getSecondaryLabel(state.value, isTransient, numConnectedDevices);
state.isAirplaneMode = mAirplaneMode.getValue() != 0;
state.isTransient = isTransient;
state.slash.isSlashed = !state.value && !state.isTransient;
@@ -140,16 +145,29 @@
}
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
- state.state = state.isAirplaneMode ? Tile.STATE_UNAVAILABLE
- : state.value || state.isTransient ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+
+ final boolean isTileUnavailable = (state.isAirplaneMode || isDataSaverEnabled);
+ final boolean isTileActive = (state.value || state.isTransient);
+
+ if (isTileUnavailable) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ } else {
+ state.state = isTileActive ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ }
+
+ state.secondaryLabel = getSecondaryLabel(
+ isTileActive, isTransient, isDataSaverEnabled, numConnectedDevices);
}
@Nullable
- private String getSecondaryLabel(
- boolean enabled, boolean isTransient, int numConnectedDevices) {
+ private String getSecondaryLabel(boolean isActive, boolean isTransient,
+ boolean isDataSaverEnabled, int numConnectedDevices) {
if (isTransient) {
return mContext.getString(R.string.quick_settings_hotspot_secondary_label_transient);
- } else if (numConnectedDevices > 0 && enabled) {
+ } else if (isDataSaverEnabled) {
+ return mContext.getString(
+ R.string.quick_settings_hotspot_secondary_label_data_saver_enabled);
+ } else if (numConnectedDevices > 0 && isActive) {
return mContext.getResources().getQuantityString(
R.plurals.quick_settings_hotspot_secondary_label_num_devices,
numConnectedDevices,
@@ -173,13 +191,23 @@
}
}
- private final class Callback implements HotspotController.Callback {
- final CallbackInfo mCallbackInfo = new CallbackInfo();
+ /**
+ * Listens to changes made to hotspot and data saver states (to toggle tile availability).
+ */
+ private final class HotspotAndDataSaverCallbacks implements HotspotController.Callback,
+ DataSaverController.Listener {
+ CallbackInfo mCallbackInfo = new CallbackInfo();
@Override
- public void onHotspotChanged(boolean enabled, int numConnectedDevices) {
- mCallbackInfo.enabled = enabled;
- mCallbackInfo.numConnectedDevices = numConnectedDevices;
+ public void onDataSaverChanged(boolean isDataSaving) {
+ mCallbackInfo.isDataSaverEnabled = isDataSaving;
+ refreshState(mCallbackInfo);
+ }
+
+ @Override
+ public void onHotspotChanged(boolean enabled, int numDevices) {
+ mCallbackInfo.isHotspotEnabled = enabled;
+ mCallbackInfo.numConnectedDevices = numDevices;
refreshState(mCallbackInfo);
}
}
@@ -189,14 +217,16 @@
* {@link #handleUpdateState(State, Object)}.
*/
protected static final class CallbackInfo {
- boolean enabled;
+ boolean isHotspotEnabled;
int numConnectedDevices;
+ boolean isDataSaverEnabled;
@Override
public String toString() {
return new StringBuilder("CallbackInfo[")
- .append("enabled=").append(enabled)
+ .append("isHotspotEnabled=").append(isHotspotEnabled)
.append(",numConnectedDevices=").append(numConnectedDevices)
+ .append(",isDataSaverEnabled=").append(isDataSaverEnabled)
.append(']').toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index df4a975..674ccd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -51,6 +51,7 @@
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
+import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
@@ -252,10 +253,13 @@
return;
}
- if (mOverviewProxyService.getProxy() != null) {
- // TODO: Proxy to Launcher
- if (!triggeredFromAltTab) {
+ IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+ if (overviewProxy != null) {
+ try {
+ overviewProxy.onOverviewShown(triggeredFromAltTab);
return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send overview show event to launcher.", e);
}
}
@@ -294,10 +298,13 @@
return;
}
- if (mOverviewProxyService.getProxy() != null) {
- // TODO: Proxy to Launcher
- if (!triggeredFromAltTab) {
+ IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+ if (overviewProxy != null) {
+ try {
+ overviewProxy.onOverviewHidden(triggeredFromAltTab, triggeredFromHomeKey);
return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send overview hide event to launcher.", e);
}
}
@@ -332,9 +339,15 @@
return;
}
- if (mOverviewProxyService.getProxy() != null) {
- // TODO: Proxy to Launcher
- return;
+ // If connected to launcher service, let it handle the toggle logic
+ IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
+ if (overviewProxy != null) {
+ try {
+ overviewProxy.onOverviewToggle();
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+ }
}
int growTarget = getComponent(Divider.class).getView().growsRecents();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 055e72e..ac26f68 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -26,6 +26,7 @@
import android.app.ActivityOptions;
import android.app.trust.TrustManager;
import android.content.ActivityNotFoundException;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -45,6 +46,8 @@
import android.widget.Toast;
+import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
import com.google.android.collect.Lists;
import com.android.internal.logging.MetricsLogger;
@@ -122,6 +125,11 @@
@Override
public void onTaskStackChangedBackground() {
+ // Skip background preloading recents in SystemUI if the overview services is bound
+ if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+ return;
+ }
+
// Check this is for the right user
if (!checkCurrentUserId(mContext, false /* debug */)) {
return;
@@ -257,6 +265,17 @@
}
});
+ private OverviewProxyService.OverviewProxyListener mOverviewProxyListener =
+ new OverviewProxyService.OverviewProxyListener() {
+ @Override
+ public void onConnectionChanged(boolean isConnected) {
+ if (!isConnected) {
+ // Clear everything when the connection to the overview service
+ Recents.getTaskLoader().onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+ }
+ }
+ };
+
public RecentsImpl(Context context) {
mContext = context;
mHandler = new Handler();
@@ -277,6 +296,11 @@
}
public void onBootCompleted() {
+ // Skip preloading tasks if we are already bound to the service
+ if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+ return;
+ }
+
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
RecentsTaskLoader loader = Recents.getTaskLoader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java
new file mode 100644
index 0000000..322a529
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2018 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.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+
+/**
+ * The guts of a notification revealed when performing a long press.
+ */
+public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsContent {
+ private static final String TAG = "AppOpsGuts";
+
+ private PackageManager mPm;
+
+ private String mPkg;
+ private String mAppName;
+ private int mAppUid;
+ private StatusBarNotification mSbn;
+ private ArraySet<Integer> mAppOps;
+ private MetricsLogger mMetricsLogger;
+ private OnSettingsClickListener mOnSettingsClickListener;
+ private NotificationGuts mGutsContainer;
+
+ private OnClickListener mOnOk = v -> {
+ closeControls(v);
+ };
+
+ public AppOpsInfo(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public interface OnSettingsClickListener {
+ void onClick(View v, String pkg, int uid, ArraySet<Integer> ops);
+ }
+
+ public void bindGuts(final PackageManager pm,
+ final OnSettingsClickListener onSettingsClick,
+ final StatusBarNotification sbn,
+ ArraySet<Integer> activeOps) {
+ mPkg = sbn.getPackageName();
+ mSbn = sbn;
+ mPm = pm;
+ mAppName = mPkg;
+ mOnSettingsClickListener = onSettingsClick;
+ mAppOps = activeOps;
+
+ bindHeader();
+ bindPrompt();
+ bindButtons();
+
+ mMetricsLogger = new MetricsLogger();
+ mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, true);
+ }
+
+ private void bindHeader() {
+ // Package name
+ Drawable pkgicon = null;
+ ApplicationInfo info;
+ try {
+ info = mPm.getApplicationInfo(mPkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (info != null) {
+ mAppUid = mSbn.getUid();
+ mAppName = String.valueOf(mPm.getApplicationLabel(info));
+ pkgicon = mPm.getApplicationIcon(info);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // app is gone, just show package name and generic icon
+ pkgicon = mPm.getDefaultActivityIcon();
+ }
+ ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
+ ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
+ }
+
+ private void bindPrompt() {
+ final TextView prompt = findViewById(R.id.prompt);
+ prompt.setText(getPromptString());
+ }
+
+ private void bindButtons() {
+ View settings = findViewById(R.id.settings);
+ settings.setOnClickListener((View view) -> {
+ mOnSettingsClickListener.onClick(view, mPkg, mAppUid, mAppOps);
+ });
+ TextView ok = findViewById(R.id.ok);
+ ok.setOnClickListener(mOnOk);
+ }
+
+ private String getPromptString() {
+ String cameraString =
+ mContext.getResources().getString(R.string.notification_appops_camera_active);
+ String micString =
+ mContext.getResources().getString(R.string.notification_appops_microphone_active);
+ String overlayString =
+ mContext.getResources().getString(R.string.notification_appops_overlay_active);
+ String using = null;
+ String promptString;
+ if (mAppOps.contains(AppOpsManager.OP_CAMERA)
+ && mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) {
+ using = mContext.getResources().getQuantityString(
+ R.plurals.notification_using, 2, micString, cameraString);
+ } else if (mAppOps.contains(AppOpsManager.OP_CAMERA)) {
+ using = mContext.getResources().getQuantityString(
+ R.plurals.notification_using, 1, cameraString);
+ } else if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)){
+ using = mContext.getResources().getQuantityString(
+ R.plurals.notification_using, 1, micString);
+ }
+
+ if (mAppOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)) {
+ if (using != null) {
+ promptString = mContext.getResources().getQuantityString(
+ R.plurals.notification_appops, 2, overlayString, using);
+ } else {
+ promptString = mContext.getResources().getQuantityString(
+ R.plurals.notification_appops, 1, overlayString);
+ }
+ } else {
+ promptString = mContext.getResources().getQuantityString(
+ R.plurals.notification_appops, 1, using);
+ }
+
+ return promptString;
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ if (mGutsContainer != null &&
+ event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+ if (mGutsContainer.isExposed()) {
+ event.getText().add(mContext.getString(
+ R.string.notification_channel_controls_opened_accessibility, mAppName));
+ } else {
+ event.getText().add(mContext.getString(
+ R.string.notification_channel_controls_closed_accessibility, mAppName));
+ }
+ }
+ }
+
+ private void closeControls(View v) {
+ mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ mGutsContainer.getLocationOnScreen(parentLoc);
+ v.getLocationOnScreen(targetLoc);
+ final int centerX = v.getWidth() / 2;
+ final int centerY = v.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+ mGutsContainer.closeControls(x, y, false, false);
+ }
+
+ @Override
+ public void setGutsParent(NotificationGuts guts) {
+ mGutsContainer = guts;
+ }
+
+ @Override
+ public boolean willBeRemoved() {
+ return false;
+ }
+
+ @Override
+ public View getContentView() {
+ return this;
+ }
+
+ @Override
+ public boolean handleCloseControls(boolean save, boolean force) {
+ return false;
+ }
+
+ @Override
+ public int getActualHeight() {
+ return getHeight();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 785fc1c..e5c5dcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -25,8 +25,8 @@
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
@@ -188,6 +188,7 @@
private boolean mShowNoBackground;
private ExpandableNotificationRow mNotificationParent;
private OnExpandClickListener mOnExpandClickListener;
+ private View.OnClickListener mOnAppOpsClickListener;
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -890,6 +891,7 @@
ArrayList<MenuItem> items = new ArrayList<>();
items.add(NotificationMenuRow.createInfoItem(mContext));
items.add(NotificationMenuRow.createSnoozeItem(mContext));
+ items.add(NotificationMenuRow.createAppOpsItem(mContext));
mMenuRow.setMenuItems(items);
}
if (existed) {
@@ -1363,6 +1365,20 @@
mPublicLayout.showAppOpsIcons(activeOps);
}
+ public View.OnClickListener getAppOpsOnClickListener() {
+ return mOnAppOpsClickListener;
+ }
+
+ protected void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
+ mOnAppOpsClickListener = v -> {
+ createMenu();
+ MenuItem menuItem = getProvider().getAppOpsMenuItem(mContext);
+ if (menuItem != null) {
+ l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem);
+ }
+ };
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -2658,4 +2674,15 @@
*/
boolean onLongPress(View v, int x, int y, MenuItem item);
}
+
+ /**
+ * Equivalent to View.OnClickListener with coordinates
+ */
+ public interface OnAppOpsClickListener {
+ /**
+ * Equivalent to {@link View.OnClickListener#onClick(View)} with coordinates
+ * @return whether the click was handled
+ */
+ boolean onClick(View v, int x, int y, MenuItem item);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index bc14203..859dc39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -58,6 +58,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.NumberFormat;
+import java.util.IllegalFormatConversionException;
/**
* Controls the indications and error messages shown on the Keyguard
@@ -414,11 +415,24 @@
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
if (hasChargingTime) {
+ // We now have battery percentage in these strings and it's expected that all
+ // locales will also have it in the future. For now, we still have to support the old
+ // format until all languages get the new translations.
String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, chargingTimeRemaining);
- return mContext.getResources().getString(chargingId, chargingTimeFormatted, percentage);
+ try {
+ return mContext.getResources().getString(chargingId, chargingTimeFormatted,
+ percentage);
+ } catch (IllegalFormatConversionException e) {
+ return mContext.getResources().getString(chargingId, chargingTimeFormatted);
+ }
} else {
- return mContext.getResources().getString(chargingId, percentage);
+ // Same as above
+ try {
+ return mContext.getResources().getString(chargingId, percentage);
+ } catch (IllegalFormatConversionException e) {
+ return mContext.getResources().getString(chargingId);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index d53cb03..22a186f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -16,6 +16,13 @@
package com.android.systemui.statusbar;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.Notification;
@@ -445,20 +452,47 @@
return Ranking.VISIBILITY_NO_OVERRIDE;
}
- public boolean shouldSuppressScreenOff(String key) {
+ public boolean shouldSuppressFullScreenIntent(String key) {
if (mRankingMap != null) {
getRanking(key, mTmpRanking);
return (mTmpRanking.getSuppressedVisualEffects()
- & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0;
+ & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0;
}
return false;
}
- public boolean shouldSuppressScreenOn(String key) {
+ public boolean shouldSuppressPeek(String key) {
if (mRankingMap != null) {
getRanking(key, mTmpRanking);
return (mTmpRanking.getSuppressedVisualEffects()
- & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
+ & SUPPRESSED_EFFECT_PEEK) != 0;
+ }
+ return false;
+ }
+
+ public boolean shouldSuppressStatusBar(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return (mTmpRanking.getSuppressedVisualEffects()
+ & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
+ }
+ return false;
+ }
+
+ public boolean shouldSuppressAmbient(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return (mTmpRanking.getSuppressedVisualEffects()
+ & SUPPRESSED_EFFECT_AMBIENT) != 0;
+ }
+ return false;
+ }
+
+ public boolean shouldSuppressNotificationList(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return (mTmpRanking.getSuppressedVisualEffects()
+ & SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
}
return false;
}
@@ -576,6 +610,14 @@
return true;
}
+ if (mEnvironment.isDozing() && shouldSuppressAmbient(sbn.getKey())) {
+ return true;
+ }
+
+ if (!mEnvironment.isDozing() && shouldSuppressNotificationList(sbn.getKey())) {
+ return true;
+ }
+
if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS
&& mGroupManager.isChildInGroupWithSummary(sbn)) {
return true;
@@ -670,5 +712,9 @@
public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
public String getCurrentMediaNotificationKey();
public NotificationGroupManager getGroupManager();
+ /**
+ * @return true iff the device is dozing
+ */
+ boolean isDozing();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 71f7911..48828ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -124,6 +124,7 @@
protected boolean mUseHeadsUp = false;
protected boolean mDisableNotificationAlerts;
protected NotificationListContainer mListContainer;
+ private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private final class NotificationClicker implements View.OnClickListener {
@@ -271,6 +272,7 @@
mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
mHeadsUpObserver.onChange(true); // set up
+ mOnAppOpsClickListener = mGutsManager::openGuts;
}
public NotificationData getNotificationData() {
@@ -302,11 +304,7 @@
return true;
}
- if (mPowerManager.isInteractive()) {
- return mNotificationData.shouldSuppressScreenOn(key);
- } else {
- return mNotificationData.shouldSuppressScreenOff(key);
- }
+ return mNotificationData.shouldSuppressFullScreenIntent(key);
}
private void inflateViews(NotificationData.Entry entry, ViewGroup parent) {
@@ -361,6 +359,8 @@
row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
+ row.setAppOpsOnClickListener(mOnAppOpsClickListener);
+
mCallback.onBindRow(entry, pmUser, sbn, row);
}
@@ -622,7 +622,7 @@
}
}
- private void updateNotification(NotificationData.Entry entry, PackageManager pmUser,
+ protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
row.setNeedsRedaction(mLockscreenUserManager.needsRedaction(entry));
boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
@@ -845,12 +845,13 @@
return false;
}
- if (!mPresenter.isDozing() && mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
+ if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(sbn.getKey())) {
if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
return false;
}
- if (mPresenter.isDozing() && mNotificationData.shouldSuppressScreenOff(sbn.getKey())) {
+ // Peeking triggers an ambient display pulse, so disable peek is ambient is active
+ if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(sbn.getKey())) {
if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index f730601..9b2f939 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -15,9 +15,13 @@
*/
package com.android.systemui.statusbar;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEGATIVE;
+import android.app.AppOpsManager;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.content.Context;
@@ -147,6 +151,23 @@
mPresenter.startNotificationGutsIntent(intent, appUid, row);
}
+ protected void startAppOpsSettingsActivity(String pkg, int uid, ArraySet<Integer> ops,
+ ExpandableNotificationRow row) {
+ if (ops.contains(OP_SYSTEM_ALERT_WINDOW)) {
+ if (ops.contains(OP_CAMERA) || ops.contains(OP_RECORD_AUDIO)) {
+ startAppNotificationSettingsActivity(pkg, uid, null, row);
+ } else {
+ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+ intent.setData(Uri.fromParts("package", pkg, null));
+ mPresenter.startNotificationGutsIntent(intent, uid, row);
+ }
+ } else if (ops.contains(OP_CAMERA) || ops.contains(OP_RECORD_AUDIO)) {
+ Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, pkg);
+ mPresenter.startNotificationGutsIntent(intent, uid, row);
+ }
+ }
+
public void bindGuts(final ExpandableNotificationRow row) {
bindGuts(row, mGutsMenuItem);
}
@@ -185,6 +206,22 @@
});
}
+ if (gutsView instanceof AppOpsInfo) {
+ AppOpsInfo info = (AppOpsInfo) gutsView;
+ final UserHandle userHandle = sbn.getUser();
+ PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
+ userHandle.getIdentifier());
+ final AppOpsInfo.OnSettingsClickListener onSettingsClick = (View v,
+ String pkg, int uid, ArraySet<Integer> ops) -> {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_OPS_GUTS_SETTINGS);
+ guts.resetFalsingCheck();
+ startAppOpsSettingsActivity(pkg, uid, ops, row);
+ };
+ if (!row.getEntry().mActiveAppOps.isEmpty()) {
+ info.bindGuts(pmUser, onSettingsClick, sbn, row.getEntry().mActiveAppOps);
+ }
+ }
+
if (gutsView instanceof NotificationInfo) {
final UserHandle userHandle = sbn.getUser();
PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index afe906c..b1ad30c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import android.animation.Animator;
@@ -39,6 +40,7 @@
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -73,6 +75,7 @@
private boolean mNonblockable;
private StatusBarNotification mSbn;
private AnimatorSet mExpandAnimation;
+ private boolean mIsForeground;
private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
@@ -84,7 +87,7 @@
closeControls(v);
};
- private OnClickListener mOnStopNotifications = v -> {
+ private OnClickListener mOnStopMinNotifications = v -> {
swapContent(false);
};
@@ -150,6 +153,8 @@
mSingleNotificationChannel = notificationChannel;
mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
mNegativeUserSentiment = negativeUserSentiment;
+ mIsForeground =
+ (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
@@ -290,14 +295,23 @@
private void bindButtons() {
View block = findViewById(R.id.block);
- block.setOnClickListener(mOnStopNotifications);
+ block.setOnClickListener(mOnStopMinNotifications);
TextView keep = findViewById(R.id.keep);
keep.setOnClickListener(mOnKeepShowing);
findViewById(R.id.undo).setOnClickListener(mOnUndo);
+ View minimize = findViewById(R.id.minimize);
+ minimize.setOnClickListener(mOnStopMinNotifications);
if (mNonblockable) {
keep.setText(R.string.notification_done);
block.setVisibility(GONE);
+ minimize.setVisibility(GONE);
+ } else if (mIsForeground) {
+ block.setVisibility(GONE);
+ minimize.setVisibility(VISIBLE);
+ } else if (!mIsForeground) {
+ block.setVisibility(VISIBLE);
+ minimize.setVisibility(GONE);
}
// app settings link
@@ -306,7 +320,7 @@
mSbn.getId(), mSbn.getTag());
if (settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
- settingsLinkView.setVisibility(View.VISIBLE);
+ settingsLinkView.setVisibility(VISIBLE);
settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
mSbn.getNotification().getSettingsText()));
settingsLinkView.setOnClickListener((View view) -> {
@@ -322,14 +336,21 @@
mExpandAnimation.cancel();
}
+ View prompt = findViewById(R.id.prompt);
+ ViewGroup confirmation = findViewById(R.id.confirmation);
+ TextView confirmationText = findViewById(R.id.confirmation_text);
+ View header = findViewById(R.id.header);
+
if (showPrompt) {
mChosenImportance = mStartingUserImportance;
+ } else if (mIsForeground) {
+ mChosenImportance = IMPORTANCE_MIN;
+ confirmationText.setText(R.string.notification_channel_minimized);
} else {
mChosenImportance = IMPORTANCE_NONE;
+ confirmationText.setText(R.string.notification_channel_disabled);
}
- View prompt = findViewById(R.id.prompt);
- View confirmation = findViewById(R.id.confirmation);
ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
prompt.getAlpha(), showPrompt ? 1f : 0f);
promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
@@ -339,6 +360,7 @@
prompt.setVisibility(showPrompt ? VISIBLE : GONE);
confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+ header.setVisibility(showPrompt ? VISIBLE : GONE);
mExpandAnimation = new AnimatorSet();
mExpandAnimation.playTogether(promptAnim, confirmAnim);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 037eeb2..0eb6bd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -30,6 +30,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
@@ -68,6 +69,7 @@
private Context mContext;
private FrameLayout mMenuContainer;
private MenuItem mInfoItem;
+ private MenuItem mAppOpsItem;
private ArrayList<MenuItem> mMenuItems;
private OnMenuEventListener mMenuListener;
@@ -121,6 +123,11 @@
}
@Override
+ public MenuItem getAppOpsMenuItem(Context context) {
+ return mAppOpsItem;
+ }
+
+ @Override
public void setSwipeActionHelper(NotificationSwipeActionHelper helper) {
mSwipeHelper = helper;
}
@@ -189,6 +196,9 @@
mInfoItem = createInfoItem(mContext);
mMenuItems.add(mInfoItem);
+ mAppOpsItem = createAppOpsItem(mContext);
+ mMenuItems.add(mAppOpsItem);
+
// Construct the menu views
if (mMenuContainer != null) {
mMenuContainer.removeAllViews();
@@ -614,6 +624,14 @@
return info;
}
+ public static MenuItem createAppOpsItem(Context context) {
+ AppOpsInfo appOpsContent = (AppOpsInfo) LayoutInflater.from(context).inflate(
+ R.layout.app_ops_info, null, false);
+ MenuItem info = new NotificationMenuItem(context, null, appOpsContent,
+ -1 /*don't show in slow swipe menu */);
+ return info;
+ }
+
private void addMenuView(MenuItem item, ViewGroup parent) {
View menuView = item.getMenuView();
if (menuView != null) {
@@ -631,22 +649,29 @@
GutsContent mGutsContent;
String mContentDescription;
+ /**
+ * Add a new 'guts' panel. If iconResId < 0 it will not appear in the slow swipe menu
+ * but can still be exposed via other affordances.
+ */
public NotificationMenuItem(Context context, String s, GutsContent content, int iconResId) {
Resources res = context.getResources();
int padding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
int tint = res.getColor(R.color.notification_gear_color);
- AlphaOptimizedImageView iv = new AlphaOptimizedImageView(context);
- iv.setPadding(padding, padding, padding, padding);
- Drawable icon = context.getResources().getDrawable(iconResId);
- iv.setImageDrawable(icon);
- iv.setColorFilter(tint);
- iv.setAlpha(1f);
- mMenuView = iv;
+ if (iconResId >= 0) {
+ AlphaOptimizedImageView iv = new AlphaOptimizedImageView(context);
+ iv.setPadding(padding, padding, padding, padding);
+ Drawable icon = context.getResources().getDrawable(iconResId);
+ iv.setImageDrawable(icon);
+ iv.setColorFilter(tint);
+ iv.setAlpha(1f);
+ mMenuView = iv;
+ }
mContentDescription = s;
mGutsContent = content;
}
@Override
+ @Nullable
public View getMenuView() {
return mMenuView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 5263bb4..21d3d81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -101,11 +101,6 @@
void updateNotificationViews();
/**
- * @return true iff the device is dozing
- */
- boolean isDozing();
-
- /**
* Returns the maximum number of notifications to show while locked.
*
* @param recompute whether something has changed that means we should recompute this value
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
new file mode 100644
index 0000000..5c21fd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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.content.Context;
+import android.database.ContentObserver;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.provider.Settings;
+
+public class VibratorHelper {
+
+ private final Vibrator mVibrator;
+ private final Context mContext;
+ private boolean mHapticFeedbackEnabled;
+
+ final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateHapticFeedBackEnabled();
+ }
+ };
+
+ public VibratorHelper(Context context) {
+ mContext = context;
+ mVibrator = context.getSystemService(Vibrator.class);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true,
+ mVibrationObserver);
+ mVibrationObserver.onChange(false /* selfChange */);
+ }
+
+ public void vibrate(final int effectId) {
+ if (mHapticFeedbackEnabled) {
+ AsyncTask.execute(() ->
+ mVibrator.vibrate(VibrationEffect.get(effectId, false /* fallback */)));
+ }
+ }
+
+ private void updateHapticFeedBackEnabled() {
+ mHapticFeedbackEnabled = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index b95b8a3..dfcd5e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -98,6 +98,7 @@
}, TRANSFORMING_VIEW_TITLE);
resolveHeaderViews();
updateInvertHelper();
+ addAppOpsOnClickListener(row);
}
@Override
@@ -121,6 +122,10 @@
getDozer().setColor(mColor);
}
+ private void addAppOpsOnClickListener(ExpandableNotificationRow row) {
+ mNotificationHeader.setAppOpsOnClickListener(row.getAppOpsOnClickListener());
+ }
+
private int resolveColor(ImageView icon) {
if (icon != null && icon.getDrawable() != null) {
ColorFilter filter = icon.getDrawable().getColorFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index edfbd3f..1109955 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -20,6 +20,7 @@
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.MathUtils;
import android.util.Slog;
import android.util.StatsLog;
import android.view.KeyEvent;
@@ -49,7 +50,8 @@
*/
public class KeyguardBouncer {
- final static private String TAG = "KeyguardBouncer";
+ private static final String TAG = "KeyguardBouncer";
+ static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
@@ -86,13 +88,25 @@
}
public void show(boolean resetSecuritySelection) {
+ show(resetSecuritySelection, true /* notifyFalsing */);
+ }
+
+ public void show(boolean resetSecuritySelection, boolean notifyFalsing) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
return;
}
- mFalsingManager.onBouncerShown();
ensureView();
+
+ // On the keyguard, we want to show the bouncer when the user drags up, but it's
+ // not correct to end the falsing session. We still need to verify if those touches
+ // are valid.
+ // Later, at the end of the animation, when the bouncer is at the top of the screen,
+ // onFullyShown() will be called and FalsingManager will stop recording touches.
+ if (notifyFalsing) {
+ mFalsingManager.onBouncerShown();
+ }
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
// case we are already showing and the current security method changed.
@@ -126,6 +140,28 @@
mCallback.onBouncerVisiblityChanged(true /* shown */);
}
+ /**
+ * This method must be called at the end of the bouncer animation when
+ * the translation is performed manually by the user, otherwise FalsingManager
+ * will never be notified and its internal state will be out of sync.
+ */
+ public void onFullyShown() {
+ mFalsingManager.onBouncerShown();
+ }
+
+ /**
+ * This method must be called at the end of the bouncer animation when
+ * the translation is performed manually by the user, otherwise FalsingManager
+ * will never be notified and its internal state will be out of sync.
+ */
+ public void onFullyHidden() {
+ if (!mShowingSoon) {
+ cancelShowRunnable();
+ inflateView();
+ mFalsingManager.onBouncerHidden();
+ }
+ }
+
private final Runnable mShowRunnable = new Runnable() {
@Override
public void run() {
@@ -247,6 +283,18 @@
mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
+ /**
+ * Current notification panel expansion
+ * @param fraction 0 when notification panel is collapsed and 1 when expanded.
+ * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
+ */
+ public void setExpansion(float fraction) {
+ if (mKeyguardView != null) {
+ mKeyguardView.setAlpha(MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction));
+ mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
+ }
+ }
+
protected void ensureView() {
// Removal of the view might be deferred to reduce unlock latency,
// in this case we need to force the removal, otherwise we'll
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 0cf26df..1bd5e33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -79,14 +79,9 @@
private int mMaxShadeBottom;
/**
- * Margin that we should respect within the available space.
+ * Minimum distance from the status bar.
*/
- private int mContainerPadding;
-
- /**
- * Position where clock should be when the panel is collapsed.
- */
- private int mClockYTarget;
+ private int mContainerTopPadding;
/**
* @see NotificationPanelView#getMaxPanelHeight()
@@ -109,12 +104,22 @@
private float mDarkAmount;
/**
+ * If keyguard will require a password or just fade away.
+ */
+ private boolean mCurrentlySecure;
+
+ /**
+ * If notification panel view currently has a touch.
+ */
+ private boolean mTracking;
+
+ /**
* Refreshes the dimension values.
*/
public void loadDimens(Resources res) {
mClockNotificationsMargin = res.getDimensionPixelSize(
R.dimen.keyguard_clock_notifications_margin);
- mContainerPadding = res.getDimensionPixelSize(
+ mContainerTopPadding = res.getDimensionPixelSize(
R.dimen.keyguard_clock_top_margin);
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_x);
@@ -124,8 +129,8 @@
public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
- float dark) {
- mMinTopMargin = minTopMargin;
+ float dark, boolean secure, boolean tracking) {
+ mMinTopMargin = minTopMargin + mContainerTopPadding;
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
mExpandedHeight = expandedHeight;
@@ -133,13 +138,8 @@
mHeight = parentHeight;
mKeyguardStatusHeight = keyguardStatusHeight;
mDarkAmount = dark;
-
- // Where the clock should stop when swiping up.
- // This should be outside of the display when unlocked or
- // under then status bar when the bouncer will be shown
- mClockYTarget = -mKeyguardStatusHeight;
- // TODO: on bouncer animation follow-up CL
- // mClockYTarget = mMinTopMargin + mContainerPadding;
+ mCurrentlySecure = secure;
+ mTracking = tracking;
}
public void run(Result result) {
@@ -173,8 +173,8 @@
float y = containerCenter - mKeyguardStatusHeight * CLOCK_HEIGHT_WEIGHT
- mClockNotificationsMargin - mNotificationStackHeight / 2;
- if (y < mMinTopMargin + mContainerPadding) {
- y = mMinTopMargin + mContainerPadding;
+ if (y < mMinTopMargin) {
+ y = mMinTopMargin;
}
// Don't allow the clock base to be under half of the screen
@@ -190,18 +190,32 @@
// Dark: Align the bottom edge of the clock at about half of the screen:
final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
float clockYRegular = getExpandedClockPosition();
+ float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight;
// Move clock up while collapsing the shade
final float shadeExpansion = mExpandedHeight / mMaxPanelHeight;
- final float clockY = MathUtils.lerp(mClockYTarget, clockYRegular, shadeExpansion);
+ final float clockY = MathUtils.lerp(clockYTarget, clockYRegular, shadeExpansion);
return (int) MathUtils.lerp(clockY, clockYDark, mDarkAmount);
}
+ /**
+ * We might want to fade out the clock when the user is swiping up.
+ * One exception is when the bouncer will become visible, in this cause the clock
+ * should always persist.
+ *
+ * @param y Current clock Y.
+ * @return Alpha from 0 to 1.
+ */
private float getClockAlpha(int y) {
- float alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
- / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
- alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
+ float alphaKeyguard;
+ if (mCurrentlySecure) {
+ alphaKeyguard = 1;
+ } else {
+ alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
+ / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
+ alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
+ }
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
}
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 c5269ad..1361cc4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -29,21 +28,19 @@
import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
-import com.android.internal.statusbar.StatusBarIcon;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
-import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -210,18 +207,26 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
- private void updateLayoutConsideringCutout() {
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (updateLayoutConsideringCutout()) {
+ requestLayout();
+ }
+ return super.onApplyWindowInsets(insets);
+ }
+
+ private boolean updateLayoutConsideringCutout() {
DisplayCutout dc = getRootWindowInsets().getDisplayCutout();
if (dc == null) {
- updateLayoutParamsNoCutout();
+ return updateLayoutParamsNoCutout();
} else {
- updateLayoutParamsForCutout(dc);
+ return updateLayoutParamsForCutout(dc);
}
}
- private void updateLayoutParamsNoCutout() {
+ private boolean updateLayoutParamsNoCutout() {
if (mLayoutState == LAYOUT_NO_CUTOUT) {
- return;
+ return false;
}
mLayoutState = LAYOUT_NO_CUTOUT;
@@ -240,11 +245,12 @@
(LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
llp.setMarginStart(getResources().getDimensionPixelSize(
R.dimen.system_icons_super_container_margin_start));
+ return true;
}
- private void updateLayoutParamsForCutout(DisplayCutout dc) {
+ private boolean updateLayoutParamsForCutout(DisplayCutout dc) {
if (mLayoutState == LAYOUT_CUTOUT) {
- return;
+ return false;
}
mLayoutState = LAYOUT_CUTOUT;
@@ -268,6 +274,7 @@
LinearLayout.LayoutParams llp =
(LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
llp.setMarginStart(0);
+ return true;
}
//TODO: Something is setting signal_cluster to MATCH_PARENT. Why?
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 3b080cf..ca5a350 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,6 +39,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
+import android.os.VibrationEffect;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
import android.util.Log;
@@ -67,6 +68,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.TintedKeyButtonDrawable;
@@ -79,6 +81,7 @@
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
@@ -106,6 +109,7 @@
private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
private Rect mHomeButtonBounds = new Rect();
private Rect mBackButtonBounds = new Rect();
+ private Rect mRecentsButtonBounds = new Rect();
private int[] mTmpPosition = new int[2];
private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
@@ -117,7 +121,7 @@
private KeyButtonDrawable mImeIcon;
private KeyButtonDrawable mMenuIcon;
private KeyButtonDrawable mAccessibilityIcon;
- private KeyButtonDrawable mRotateSuggestionIcon;
+ private TintedKeyButtonDrawable mRotateSuggestionIcon;
private GestureHelper mGestureHelper;
private DeadZone mDeadZone;
@@ -146,6 +150,7 @@
private Divider mDivider;
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
+ private final VibratorHelper mVibratorHelper;
private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
@@ -241,6 +246,7 @@
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
+ mVibratorHelper = new VibratorHelper(context);
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -306,7 +312,12 @@
mDownHitTarget = HIT_TARGET_BACK;
} else if (mHomeButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_HOME;
+ } else if (mRecentsButtonBounds.contains(x, y)) {
+ mDownHitTarget = HIT_TARGET_OVERVIEW;
}
+
+ // Vibrate tick whenever down occurs on navigation bar
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
break;
}
return mGestureHelper.onInterceptTouchEvent(event);
@@ -479,7 +490,7 @@
darkContext.getDrawable(darkIcon));
}
- private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon,
+ private TintedKeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon,
@ColorInt int lightColor, @ColorInt int darkColor) {
return TintedKeyButtonDrawable.create(ctx.getDrawable(icon), lightColor, darkColor);
}
@@ -745,8 +756,15 @@
Context rotateContext = new ContextThemeWrapper(ctx, style);
// Recreate the icon and set it if needed
+ TintedKeyButtonDrawable priorIcon = mRotateSuggestionIcon;
mRotateSuggestionIcon = getDrawable(rotateContext, R.drawable.ic_sysbar_rotate_button,
lightColor, darkColor);
+
+ // Apply any prior set dark intensity
+ if (priorIcon != null && priorIcon.isDarkIntensitySet()) {
+ mRotateSuggestionIcon.setDarkIntensity(priorIcon.getDarkIntensity());
+ }
+
if (setIcon) getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
}
@@ -816,6 +834,7 @@
super.onLayout(changed, left, top, right, bottom);
updateButtonLocationOnScreen(getBackButton(), mBackButtonBounds);
updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
+ updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
mGestureHelper.onLayout(changed, left, top, right, bottom);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
index 1452e0c..e5083c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
@@ -95,8 +95,12 @@
}
private View findNearestChild(MotionEvent event) {
- return mClickableChildren.stream().map(v -> new Pair<>(distance(v, event), v))
- .min(Comparator.comparingInt(f -> f.first)).get().second;
+ return mClickableChildren
+ .stream()
+ .filter(v -> v.isAttachedToWindow())
+ .map(v -> new Pair<>(distance(v, event), v))
+ .min(Comparator.comparingInt(f -> f.first))
+ .get().second;
}
private int distance(View v, MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e77b135..e1aed7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -141,7 +141,7 @@
}
// showAmbient == show in shade but not shelf
- if (!showAmbient && notificationData.shouldSuppressScreenOn(entry.key)) {
+ if (!showAmbient && notificationData.shouldSuppressStatusBar(entry.key)) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9d2480b..2711d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -238,7 +238,6 @@
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mNoVisibleNotifications = true;
private ValueAnimator mDarkAnimator;
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private boolean mUserSetupComplete;
private int mQsNotificationTopPadding;
private float mExpandOffset;
@@ -265,10 +264,8 @@
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
- mNotificationContainerParent = (NotificationsQuickSettingsContainer)
- findViewById(R.id.notification_container_parent);
- mNotificationStackScroller = (NotificationStackScrollLayout)
- findViewById(R.id.notification_stack_scroller);
+ mNotificationContainerParent = findViewById(R.id.notification_container_parent);
+ mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
@@ -470,7 +467,9 @@
getMaxPanelHeight(),
totalHeight,
mKeyguardStatusView.getHeight(),
- mDarkAmount);
+ mDarkAmount,
+ mStatusBar.isKeyguardCurrentlySecure(),
+ mTracking);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -1710,7 +1709,16 @@
}
private void updateKeyguardBottomAreaAlpha() {
- float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
+ // There are two possible panel expansion behaviors:
+ // • User dragging up to unlock: we want to fade out as quick as possible
+ // (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area.
+ // • User tapping on lock screen: bouncer won't be visible but panel expansion will
+ // change due to "unlock hint animation." In this case, fading out the bottom area
+ // would also hide the message that says "swipe to unlock," we don't want to do that.
+ float expansionAlpha = MathUtils.map(isUnlockHintRunning()
+ ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
+ 0f, 1f, getExpandedFraction());
+ float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
@@ -1809,7 +1817,7 @@
@Override
protected void onTrackingStarted() {
- mFalsingManager.onTrackingStarted();
+ mFalsingManager.onTrackingStarted(mStatusBar.isKeyguardCurrentlySecure());
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
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 cefe972..b448967 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -27,6 +27,7 @@
public static final boolean DEBUG = false;
public static final String TAG = PanelBar.class.getSimpleName();
private static final boolean SPEW = false;
+ private boolean mBouncerShowing;
public static final void LOG(String fmt, Object... args) {
if (!DEBUG) return;
@@ -65,6 +66,7 @@
}
public void setBouncerShowing(boolean showing) {
+ mBouncerShowing = showing;
int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@@ -122,7 +124,7 @@
boolean fullyOpened = false;
if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
PanelView pv = mPanel;
- pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
+ pv.setVisibility(expanded || mBouncerShowing ? VISIBLE : INVISIBLE);
// adjust any other panels that may be partially visible
if (expanded) {
if (mState == STATE_CLOSED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 9c2a0e5..3de0a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,14 +23,8 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.os.AsyncTask;
-import android.os.Handler;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -50,10 +44,11 @@
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.VibratorHelper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.function.BiConsumer;
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
@@ -66,9 +61,9 @@
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mPanelUpdateWhenAnimatorEnds;
private boolean mVibrateOnOpening;
- private boolean mVibrationEnabled;
protected boolean mLaunchingNotification;
private int mFixedDuration = NO_FIXED_DURATION;
+ private BiConsumer<Float, Boolean> mExpansionListener;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -110,13 +105,7 @@
private FlingAnimationUtils mFlingAnimationUtilsClosing;
private FlingAnimationUtils mFlingAnimationUtilsDismissing;
private FalsingManager mFalsingManager;
- private final Vibrator mVibrator;
- final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) {
- @Override
- public void onChange(boolean selfChange) {
- updateHapticFeedBackEnabled();
- }
- };
+ private final VibratorHelper mVibratorHelper;
/**
* Whether an instant expand request is currently pending and we are just waiting for layout.
@@ -218,18 +207,9 @@
mFalsingManager = FalsingManager.getInstance(context);
mNotificationsDragEnabled =
getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
- mVibrator = mContext.getSystemService(Vibrator.class);
+ mVibratorHelper = new VibratorHelper(context);
mVibrateOnOpening = mContext.getResources().getBoolean(
R.bool.config_vibrateOnIconAnimation);
- mContext.getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true,
- mVibrationObserver);
- mVibrationObserver.onChange(false /* selfChange */);
- }
-
- public void updateHapticFeedBackEnabled() {
- mVibrationEnabled = Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
}
protected void loadDimens() {
@@ -341,7 +321,8 @@
cancelPeek();
onTrackingStarted();
}
- if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
+ if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
+ && !mStatusBar.isBouncerShowing()) {
startOpening(event);
}
break;
@@ -421,9 +402,8 @@
runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
false /* collapseWhenFinished */);
notifyBarPanelExpansionChanged();
- if (mVibrateOnOpening && mVibrationEnabled) {
- AsyncTask.execute(() ->
- mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)));
+ if (mVibrateOnOpening) {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
}
//TODO: keyguard opens QS a different way; log that too?
@@ -506,7 +486,8 @@
if (mUpdateFlingOnLayout) {
mUpdateFlingVelocity = vel;
}
- } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
+ } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
+ && !mStatusBar.isBouncerShowing()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
// Lets show the user that he can actually expand the panel
@@ -515,7 +496,7 @@
// We need to collapse the panel since we peeked to the small height.
postOnAnimation(mPostCollapseRunnable);
}
- } else {
+ } else if (!mStatusBar.isBouncerShowing()) {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
}
@@ -1115,6 +1096,10 @@
mStatusBar.onUnlockHintStarted();
}
+ public boolean isUnlockHintRunning() {
+ return mHintAnimationRunning;
+ }
+
/**
* Phase 1: Move everything upwards.
*/
@@ -1206,6 +1191,13 @@
mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
|| mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
|| mTracking || mHeightAnimator != null);
+ if (mExpansionListener != null) {
+ mExpansionListener.accept(mExpandedFraction, mTracking);
+ }
+ }
+
+ public void setExpansionListener(BiConsumer<Float, Boolean> consumer) {
+ mExpansionListener = consumer;
}
protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
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 900ec0b..cf5c1c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -28,6 +28,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
@@ -37,7 +38,8 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.util.leak.RotationUtils;
+
+import java.util.Objects;
public class PhoneStatusBarView extends PanelBar {
private static final String TAG = "PhoneStatusBarView";
@@ -98,7 +100,7 @@
// Always have Battery meters in the status bar observe the dark/light modes.
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) {
- postUpdateLayoutForCutout();
+ updateLayoutForCutout();
}
}
@@ -115,10 +117,20 @@
// May trigger cutout space layout-ing
if (updateOrientationAndCutout(newConfig.orientation)) {
- postUpdateLayoutForCutout();
+ updateLayoutForCutout();
+ requestLayout();
}
}
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (updateOrientationAndCutout(mLastOrientation)) {
+ updateLayoutForCutout();
+ requestLayout();
+ }
+ return super.onApplyWindowInsets(insets);
+ }
+
/**
*
* @param newOrientation may pass NO_VALUE for no change
@@ -133,12 +145,9 @@
}
}
- if (mDisplayCutout == null) {
- DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
- if (cutout != null) {
- changed = true;
- mDisplayCutout = cutout;
- }
+ if (!Objects.equals(getRootWindowInsets().getDisplayCutout(), mDisplayCutout)) {
+ changed = true;
+ mDisplayCutout = getRootWindowInsets().getDisplayCutout();
}
return changed;
@@ -276,17 +285,6 @@
updateSafeInsets();
}
- private void postUpdateLayoutForCutout() {
- Runnable r = new Runnable() {
- @Override
- public void run() {
- updateLayoutForCutout();
- }
- };
- // Let the cutout emulation draw first
- postDelayed(r, 0);
- }
-
private void updateCutoutLocation() {
// Not all layouts have a cutout (e.g., Car)
if (mCutoutSpace == null) {
@@ -310,40 +308,13 @@
// or letterboxing from the right or left sides.
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+ if (mDisplayCutout == null) {
lp.leftMargin = 0;
lp.rightMargin = 0;
return;
}
- int leftMargin = 0;
- int rightMargin = 0;
- switch (RotationUtils.getRotation(getContext())) {
- /*
- * Landscape: <-|
- * Seascape: |->
- */
- case RotationUtils.ROTATION_LANDSCAPE:
- leftMargin = getDisplayCutoutHeight();
- break;
- case RotationUtils.ROTATION_SEASCAPE:
- rightMargin = getDisplayCutoutHeight();
- break;
- default:
- break;
- }
-
- lp.leftMargin = leftMargin;
- lp.rightMargin = rightMargin;
- }
-
- //TODO: Find a better way
- private int getDisplayCutoutHeight() {
- if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
- return 0;
- }
-
- Rect r = mDisplayCutout.getBoundingRect();
- return r.bottom - r.top;
+ lp.leftMargin = mDisplayCutout.getSafeInsetLeft();
+ lp.rightMargin = mDisplayCutout.getSafeInsetRight();
}
}
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 e59a6b5..71376a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -35,7 +35,6 @@
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -97,14 +96,6 @@
* The most common scrim, the one under the keyguard.
*/
protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
- /**
- * We fade out the bottom scrim when the bouncer is visible.
- */
- protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
- /**
- * Opacity of the scrim behind the bouncer (the one doing actual background protection.)
- */
- protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -130,7 +121,6 @@
protected float mScrimBehindAlpha;
protected float mScrimBehindAlphaResValue;
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
- protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
// Assuming the shade is expanded during initialization
private float mExpansionFraction = 1f;
@@ -177,6 +167,7 @@
mScrimVisibleListener = scrimVisibleListener;
mContext = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
+ mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mLightBarController = lightBarController;
mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
@@ -300,10 +291,8 @@
return mState;
}
- protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
- float scrimBehindAlphaUnlocking) {
+ protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
- mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
@@ -404,9 +393,9 @@
float interpolatedFract = getInterpolatedFraction();
float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
if (mDarkenWhileDragging) {
- mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking, alphaBehind,
+ mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
interpolatedFract);
- mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
+ mCurrentInFrontAlpha = 0;
} else {
mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
interpolatedFract);
@@ -455,7 +444,8 @@
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
final GradientColors currentScrimColors;
- if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
+ if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_OCCLUDED
+ || mState == ScrimState.BOUNCER) {
// Always animate color changes if we're seeing the keyguard
mScrimInFront.setColors(mLockColors, true /* animated */);
mScrimBehind.setColors(mLockColors, true /* animated */);
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 053c5a3..58100ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -66,20 +66,31 @@
},
/**
- * Showing password challenge.
+ * Showing password challenge on the keyguard.
*/
BOUNCER(1) {
@Override
public void prepare(ScrimState previousState) {
- mCurrentBehindAlpha = ScrimController.SCRIM_BEHIND_ALPHA_UNLOCKING;
- mCurrentInFrontAlpha = ScrimController.SCRIM_IN_FRONT_ALPHA_LOCKED;
+ mCurrentBehindAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
+ mCurrentInFrontAlpha = 0f;
+ }
+ },
+
+ /**
+ * Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity.
+ */
+ BOUNCER_OCCLUDED(2) {
+ @Override
+ public void prepare(ScrimState previousState) {
+ mCurrentBehindAlpha = 0;
+ mCurrentInFrontAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
}
},
/**
* Changing screen brightness from quick settings.
*/
- BRIGHTNESS_MIRROR(2) {
+ BRIGHTNESS_MIRROR(3) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
@@ -90,7 +101,7 @@
/**
* Always on display or screen off.
*/
- AOD(3) {
+ AOD(4) {
@Override
public void prepare(ScrimState previousState) {
final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
@@ -110,7 +121,7 @@
/**
* When phone wakes up because you received a notification.
*/
- PULSING(4) {
+ PULSING(5) {
@Override
public void prepare(ScrimState previousState) {
mCurrentInFrontAlpha = 0;
@@ -125,7 +136,7 @@
/**
* Unlocked on top of an app (launcher or any other activity.)
*/
- UNLOCKED(5) {
+ UNLOCKED(6) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
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 d3fbe27..a305bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1296,7 +1296,7 @@
mDozeScrimController, keyguardViewMediator,
mScrimController, this, UnlockMethodCache.getInstance(mContext));
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
- getBouncerContainer(), mFingerprintUnlockController);
+ getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -4603,6 +4603,7 @@
if (mAmbientIndicationContainer instanceof DozeReceiver) {
((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
}
+ mEntryManager.updateNotifications();
updateDozingState();
updateReportRejectedTouchVisibility();
Trace.endSection();
@@ -4618,7 +4619,8 @@
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
if (mBouncerShowing) {
- mScrimController.transitionTo(ScrimState.BOUNCER);
+ mScrimController.transitionTo(
+ mIsOccluded ? ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER);
} else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
} else if (mBrightnessMirrorVisible) {
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 a009d80..8d536d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,10 +31,10 @@
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
@@ -75,6 +75,7 @@
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
protected StatusBar mStatusBar;
+ private NotificationPanelView mNotificationPanelView;
private FingerprintUnlockController mFingerprintUnlockController;
private ViewGroup mContainer;
@@ -88,6 +89,7 @@
protected boolean mFirstUpdate = true;
protected boolean mLastShowing;
protected boolean mLastOccluded;
+ private boolean mLastTracking;
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
@@ -124,6 +126,7 @@
public void registerStatusBar(StatusBar statusBar,
ViewGroup container,
+ NotificationPanelView notificationPanelView,
FingerprintUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
mStatusBar = statusBar;
@@ -131,6 +134,32 @@
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
+ mNotificationPanelView = notificationPanelView;
+ notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
+ }
+
+ private void onPanelExpansionChanged(float expansion, boolean tracking) {
+ // We don't want to translate the bounce when the keyguard is occluded, because we're in
+ // a FLAG_SHOW_WHEN_LOCKED activity and need to conserve the original animation.
+ // We also don't want to show the bouncer when the user quickly taps on the display.
+ final boolean noLongerTracking = mLastTracking != tracking && !tracking;
+ if (mOccluded || mNotificationPanelView.isUnlockHintRunning()) {
+ mBouncer.setExpansion(0);
+ } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
+ mBouncer.setExpansion(expansion);
+ if (expansion == 1) {
+ mBouncer.onFullyHidden();
+ updateStates();
+ } else if (!mBouncer.isShowing()) {
+ mBouncer.show(true /* resetSecuritySelection */, false /* notifyFalsing */);
+ } else if (noLongerTracking) {
+ // Notify that falsing manager should stop its session when user stops touching,
+ // even before the animation ends, to guarantee that we're not recording sensitive
+ // data.
+ mBouncer.onFullyShown();
+ }
+ }
+ mLastTracking = tracking;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 948f524..defb46c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import android.app.ActivityManager;
@@ -108,6 +110,7 @@
mLp.setTitle("StatusBar");
mLp.accessibilityTitle = mContext.getString(R.string.status_bar);
mLp.packageName = mContext.getPackageName();
+ mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mStatusBarView = statusBarView;
mBarHeight = barHeight;
mWindowManager.addView(mStatusBarView, mLp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index aec05cd..81641da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -27,12 +27,9 @@
import android.metrics.LogMaker;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.os.VibrationEffect;
-import android.os.Vibrator;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
@@ -53,6 +50,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.statusbar.VibratorHelper;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
@@ -75,7 +73,7 @@
private OnClickListener mOnClickListener;
private final KeyButtonRipple mRipple;
private final OverviewProxyService mOverviewProxyService;
- private final Vibrator mVibrator;
+ private final VibratorHelper mVibratorHelper;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final Runnable mCheckLongPress = new Runnable() {
@@ -128,7 +126,7 @@
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mRipple = new KeyButtonRipple(context, this);
- mVibrator = mContext.getSystemService(Vibrator.class);
+ mVibratorHelper = new VibratorHelper(context);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
setBackground(mRipple);
}
@@ -216,6 +214,9 @@
mGestureAborted = false;
}
if (mGestureAborted) {
+ if (mIsPressed) {
+ setPressed(false);
+ }
return false;
}
@@ -263,14 +264,17 @@
break;
case MotionEvent.ACTION_UP:
final boolean doIt = mIsPressed && !mLongClicked;
+ final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
if (isProxyConnected) {
if (doIt) {
// Animate the ripple in on touch up with setPressed and then out later
setPressed(true);
- performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ if (doHapticFeedback) {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ }
playSoundEffect(SoundEffectConstants.CLICK);
}
- } else if ((SystemClock.uptimeMillis() - mDownTime) > 150 && !mLongClicked) {
+ } else if (doHapticFeedback && !mLongClicked) {
// Always send a release ourselves because it doesn't seem to be sent elsewhere
// and it feels weird to sometimes get a release haptic and other times not.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index f0854ed..487d1c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -251,8 +251,11 @@
if (mConfig.inflateSignalStrengths) {
level++;
}
- return SignalDrawable.getState(level, getNumLevels(),
- mCurrentState.inetCondition == 0);
+ boolean dataDisabled = mCurrentState.userSetup
+ && mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
+ boolean noInternet = mCurrentState.inetCondition == 0;
+ boolean cutOut = dataDisabled || noInternet;
+ return SignalDrawable.getState(level, getNumLevels(), cutOut);
} else if (mCurrentState.enabled) {
return SignalDrawable.getEmptyState(getNumLevels());
} else {
@@ -275,6 +278,9 @@
String contentDescription = getStringIfExists(getContentDescription());
String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
+ if (mCurrentState.inetCondition == 0) {
+ dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
+ }
final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
&& mCurrentState.userSetup;
@@ -573,14 +579,13 @@
public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
- int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
- int qsDataType) {
+ int discContentDesc, int dataContentDesc, int dataType, boolean isWide) {
super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
qsDiscState, discContentDesc);
mDataContentDescription = dataContentDesc;
mDataType = dataType;
mIsWide = isWide;
- mQsDataType = qsDataType;
+ mQsDataType = dataType; // TODO: remove this field
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index aaa0568..986abef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -21,32 +21,19 @@
class TelephonyIcons {
//***** Data connection icons
-
- static final int QS_DATA_G = R.drawable.ic_qs_signal_g;
- static final int QS_DATA_3G = R.drawable.ic_qs_signal_3g;
- static final int QS_DATA_E = R.drawable.ic_qs_signal_e;
- static final int QS_DATA_H = R.drawable.ic_qs_signal_h;
- static final int QS_DATA_1X = R.drawable.ic_qs_signal_1x;
- static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g;
- static final int QS_DATA_4G_PLUS = R.drawable.ic_qs_signal_4g_plus;
- static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte;
- static final int QS_DATA_LTE_PLUS = R.drawable.ic_qs_signal_lte_plus;
-
static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
- static final int ICON_LTE = R.drawable.stat_sys_data_fully_connected_lte;
- static final int ICON_LTE_PLUS = R.drawable.stat_sys_data_fully_connected_lte_plus;
- static final int ICON_G = R.drawable.stat_sys_data_fully_connected_g;
- static final int ICON_E = R.drawable.stat_sys_data_fully_connected_e;
- static final int ICON_H = R.drawable.stat_sys_data_fully_connected_h;
- static final int ICON_3G = R.drawable.stat_sys_data_fully_connected_3g;
- static final int ICON_4G = R.drawable.stat_sys_data_fully_connected_4g;
- static final int ICON_4G_PLUS = R.drawable.stat_sys_data_fully_connected_4g_plus;
- static final int ICON_1X = R.drawable.stat_sys_data_fully_connected_1x;
-
- static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
-
- static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
+ static final int ICON_LTE = R.drawable.ic_lte_mobiledata;
+ static final int ICON_LTE_PLUS = R.drawable.ic_lte_plus_mobiledata;
+ static final int ICON_G = R.drawable.ic_g_mobiledata;
+ static final int ICON_E = R.drawable.ic_e_mobiledata;
+ static final int ICON_H = R.drawable.ic_h_mobiledata;
+ // TODO: add logic to insert H+ icon
+ static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata;
+ static final int ICON_3G = R.drawable.ic_3g_mobiledata;
+ static final int ICON_4G = R.drawable.ic_4g_mobiledata;
+ static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
+ static final int ICON_1X = R.drawable.ic_1x_mobiledata;
static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
@@ -57,11 +44,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_carrier_network_change_mode,
+ R.string.carrier_network_change_mode,
0,
- false,
- 0
- );
+ false);
static final MobileIconGroup THREE_G = new MobileIconGroup(
"3G",
@@ -72,11 +57,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_3g,
+ R.string.data_connection_3g,
TelephonyIcons.ICON_3G,
- true,
- TelephonyIcons.QS_DATA_3G
- );
+ true);
static final MobileIconGroup WFC = new MobileIconGroup(
"WFC",
@@ -87,8 +70,7 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- 0, 0, false, 0
- );
+ 0, 0, false);
static final MobileIconGroup UNKNOWN = new MobileIconGroup(
"Unknown",
@@ -99,8 +81,7 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- 0, 0, false, 0
- );
+ 0, 0, false);
static final MobileIconGroup E = new MobileIconGroup(
"E",
@@ -111,11 +92,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_edge,
+ R.string.data_connection_edge,
TelephonyIcons.ICON_E,
- false,
- TelephonyIcons.QS_DATA_E
- );
+ false);
static final MobileIconGroup ONE_X = new MobileIconGroup(
"1X",
@@ -126,11 +105,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_cdma,
+ R.string.data_connection_cdma,
TelephonyIcons.ICON_1X,
- true,
- TelephonyIcons.QS_DATA_1X
- );
+ true);
static final MobileIconGroup G = new MobileIconGroup(
"G",
@@ -141,11 +118,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_gprs,
+ R.string.data_connection_gprs,
TelephonyIcons.ICON_G,
- false,
- TelephonyIcons.QS_DATA_G
- );
+ false);
static final MobileIconGroup H = new MobileIconGroup(
"H",
@@ -156,11 +131,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_3_5g,
+ R.string.data_connection_3_5g,
TelephonyIcons.ICON_H,
- false,
- TelephonyIcons.QS_DATA_H
- );
+ false);
static final MobileIconGroup FOUR_G = new MobileIconGroup(
"4G",
@@ -171,11 +144,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_4g,
+ R.string.data_connection_4g,
TelephonyIcons.ICON_4G,
- true,
- TelephonyIcons.QS_DATA_4G
- );
+ true);
static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup(
"4G+",
@@ -186,11 +157,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_4g_plus,
+ R.string.data_connection_4g_plus,
TelephonyIcons.ICON_4G_PLUS,
- true,
- TelephonyIcons.QS_DATA_4G_PLUS
- );
+ true);
static final MobileIconGroup LTE = new MobileIconGroup(
"LTE",
@@ -201,11 +170,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_lte,
+ R.string.data_connection_lte,
TelephonyIcons.ICON_LTE,
- true,
- TelephonyIcons.QS_DATA_LTE
- );
+ true);
static final MobileIconGroup LTE_PLUS = new MobileIconGroup(
"LTE+",
@@ -216,11 +183,9 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_data_connection_lte_plus,
+ R.string.data_connection_lte_plus,
TelephonyIcons.ICON_LTE_PLUS,
- true,
- TelephonyIcons.QS_DATA_LTE_PLUS
- );
+ true);
static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
"DataDisabled",
@@ -231,10 +196,8 @@
0,
0,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- R.string.accessibility_cell_data_off,
- TelephonyIcons.ICON_DATA_DISABLED,
- false,
- TelephonyIcons.QS_ICON_DATA_DISABLED
- );
+ R.string.cell_data_off,
+ 0,
+ false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
index acf9c00..56f6726 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
@@ -30,6 +30,9 @@
private final int mLightColor;
private final int mDarkColor;
+ public static final float DARK_INTENSITY_NOT_SET = -1f;
+ private float mDarkIntensity = DARK_INTENSITY_NOT_SET;
+
public static TintedKeyButtonDrawable create(Drawable drawable, @ColorInt int lightColor,
@ColorInt int darkColor) {
return new TintedKeyButtonDrawable(new Drawable[] { drawable }, lightColor, darkColor);
@@ -39,11 +42,13 @@
super(drawables);
mLightColor = lightColor;
mDarkColor = darkColor;
+ setDarkIntensity(0f); // Set initial coloration
}
@Override
public void setDarkIntensity(float intensity) {
// Duplicate intensity scaling from KeyButtonDrawable
+ mDarkIntensity = intensity;
int intermediateColor = ColorUtils.compositeColors(
setAlphaFloat(mDarkColor, intensity),
setAlphaFloat(mLightColor,1f - intensity));
@@ -52,6 +57,16 @@
}
private int setAlphaFloat(int color, float alpha) {
- return ColorUtils.setAlphaComponent(color, (int) (alpha * 255f));
+ // Ensure alpha is clamped [0-255] or ColorUtils will crash
+ final int alphaInt = alpha > 1f ? 255 : (alpha < 0f ? 0 : ((int) alpha*255));
+ return ColorUtils.setAlphaComponent(color, alphaInt);
+ }
+
+ public boolean isDarkIntensitySet() {
+ return mDarkIntensity == DARK_INTENSITY_NOT_SET;
+ }
+
+ public float getDarkIntensity() {
+ return mDarkIntensity;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 2819624..b4c3eca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -84,8 +84,7 @@
boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
String contentDescription = getStringIfExists(getContentDescription());
if (mCurrentState.inetCondition == 0) {
- contentDescription +=
- ("," + mContext.getString(R.string.accessibility_quick_settings_no_internet));
+ contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
}
IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 716b58841..fe21f87 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -207,8 +207,6 @@
rescheduleTimeoutH();
return true;
});
- VolumeUiLayout uiLayout = VolumeUiLayout.get(mDialogView);
- uiLayout.updateRotation();
mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
mRinger = mDialog.findViewById(R.id.ringer);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
deleted file mode 100644
index 0a3a2ab..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ /dev/null
@@ -1,153 +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.volume;
-
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.DisplayCutout;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.util.leak.RotationUtils;
-
-public class VolumeUiLayout extends FrameLayout {
-
- private View mChild;
- private int mRotation = ROTATION_NONE;
- @Nullable
- private DisplayCutout mDisplayCutout;
-
- public VolumeUiLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mDisplayCutout = null;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mChild == null) {
- if (getChildCount() != 0) {
- mChild = getChildAt(0);
- updateRotation();
- } else {
- return;
- }
- }
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateRotation();
- }
-
- private void setDisplayCutout() {
- if (mDisplayCutout == null && getRootWindowInsets() != null) {
- DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
- if (cutout != null) {
- mDisplayCutout = cutout;
- }
- }
- }
-
- public void updateRotation() {
- setDisplayCutout();
- if (mChild == null) {
- if (getChildCount() != 0) {
- mChild = getChildAt(0);
- }
- }
- int rotation = RotationUtils.getRotation(getContext());
- if (rotation != mRotation) {
- updateSafeInsets(rotation);
- mRotation = rotation;
- }
- }
-
- private void updateSafeInsets(int rotation) {
- // Depending on our rotation, we may have to work around letterboxing from the right
- // side from the navigation bar or a cutout.
-
- MarginLayoutParams lp = (MarginLayoutParams) mChild.getLayoutParams();
-
- int margin = (int) getResources().getDimension(R.dimen.volume_dialog_base_margin);
- switch (rotation) {
- /*
- * Landscape: <-|. Have to deal with the nav bar
- * Seascape: |->. Have to deal with the cutout
- */
- case RotationUtils.ROTATION_LANDSCAPE:
- margin += getNavBarHeight();
- break;
- case RotationUtils.ROTATION_SEASCAPE:
- margin += getDisplayCutoutHeight();
- break;
- default:
- break;
- }
-
- lp.rightMargin = margin;
- mChild.setLayoutParams(lp);
- }
-
- private int getNavBarHeight() {
- return (int) getResources().getDimension(R.dimen.navigation_bar_size);
- }
-
- //TODO: Find a better way
- private int getDisplayCutoutHeight() {
- if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
- return 0;
- }
-
- Rect r = mDisplayCutout.getBoundingRect();
- return r.bottom - r.top;
- }
-
- @Override
- public ViewOutlineProvider getOutlineProvider() {
- return super.getOutlineProvider();
- }
-
- public static VolumeUiLayout get(View v) {
- if (v instanceof VolumeUiLayout) return (VolumeUiLayout) v;
- if (v.getParent() instanceof View) {
- return get((View) v.getParent());
- }
- return null;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsInfoTest.java
new file mode 100644
index 0000000..660d2dc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsInfoTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2018 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 static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.UiThreadTest;
+import android.util.ArraySet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@UiThreadTest
+public class AppOpsInfoTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test_package";
+ private static final int TEST_UID = 1;
+
+ private AppOpsInfo mAppOpsInfo;
+ private final PackageManager mMockPackageManager = mock(PackageManager.class);
+ private final NotificationGuts mGutsParent = mock(NotificationGuts.class);
+ private StatusBarNotification mSbn;
+
+ @Before
+ public void setUp() throws Exception {
+ // Inflate the layout
+ final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ mAppOpsInfo = (AppOpsInfo) layoutInflater.inflate(R.layout.app_ops_info, null);
+ mAppOpsInfo.setGutsParent(mGutsParent);
+
+ // PackageManager must return a packageInfo and applicationInfo.
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = TEST_PACKAGE_NAME;
+ when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()))
+ .thenReturn(packageInfo);
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = TEST_UID; // non-zero
+ when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(
+ applicationInfo);
+
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
+ new Notification(), UserHandle.CURRENT, null, 0);
+ }
+
+ @Test
+ public void testBindNotification_SetsTextApplicationName() {
+ when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, new ArraySet<>());
+ final TextView textView = mAppOpsInfo.findViewById(R.id.pkgname);
+ assertTrue(textView.getText().toString().contains("App Name"));
+ }
+
+ @Test
+ public void testBindNotification_SetsPackageIcon() {
+ final Drawable iconDrawable = mock(Drawable.class);
+ when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
+ .thenReturn(iconDrawable);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, new ArraySet<>());
+ final ImageView iconView = mAppOpsInfo.findViewById(R.id.pkgicon);
+ assertEquals(iconDrawable, iconView.getDrawable());
+ }
+
+ @Test
+ public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAppOpsInfo.bindGuts(mMockPackageManager, (View v, String pkg, int uid,
+ ArraySet<Integer> ops) -> {
+ assertEquals(TEST_PACKAGE_NAME, pkg);
+ assertEquals(expectedOps, ops);
+ assertEquals(TEST_UID, uid);
+ latch.countDown();
+ }, mSbn, expectedOps);
+
+ final View settingsButton = mAppOpsInfo.findViewById(R.id.settings);
+ settingsButton.performClick();
+ // Verify that listener was triggered.
+ assertEquals(0, latch.getCount());
+ }
+
+ @Test
+ public void testOk() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mAppOpsInfo.bindGuts(mMockPackageManager, (View v, String pkg, int uid,
+ ArraySet<Integer> ops) -> {
+ assertEquals(TEST_PACKAGE_NAME, pkg);
+ assertEquals(expectedOps, ops);
+ assertEquals(TEST_UID, uid);
+ latch.countDown();
+ }, mSbn, expectedOps);
+
+ final View okButton = mAppOpsInfo.findViewById(R.id.ok);
+ okButton.performClick();
+ assertEquals(1, latch.getCount());
+ verify(mGutsParent, times(1)).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
+ public void testPrompt_camera() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is using the camera.", prompt.getText());
+ }
+
+ @Test
+ public void testPrompt_mic() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_RECORD_AUDIO);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is using the microphone.", prompt.getText());
+ }
+
+ @Test
+ public void testPrompt_overlay() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_SYSTEM_ALERT_WINDOW);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is displaying over other apps on your screen.", prompt.getText());
+ }
+
+ @Test
+ public void testPrompt_camera_mic() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ expectedOps.add(OP_RECORD_AUDIO);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is using the microphone and camera.", prompt.getText());
+ }
+
+ @Test
+ public void testPrompt_camera_mic_overlay() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ expectedOps.add(OP_RECORD_AUDIO);
+ expectedOps.add(OP_SYSTEM_ALERT_WINDOW);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is displaying over other apps on your screen and using"
+ + " the microphone and camera.", prompt.getText());
+ }
+
+ @Test
+ public void testPrompt_camera_overlay() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_CAMERA);
+ expectedOps.add(OP_SYSTEM_ALERT_WINDOW);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is displaying over other apps on your screen and using"
+ + " the camera.", prompt.getText());
+ }
+
+ @Test
+ public void testPrompt_mic_overlay() {
+ ArraySet<Integer> expectedOps = new ArraySet<>();
+ expectedOps.add(OP_RECORD_AUDIO);
+ expectedOps.add(OP_SYSTEM_ALERT_WINDOW);
+ mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, expectedOps);
+ TextView prompt = mAppOpsInfo.findViewById(R.id.prompt);
+ assertEquals("This app is displaying over other apps on your screen and using"
+ + " the microphone.", prompt.getText());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index ce629bb..34e444e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -153,14 +154,15 @@
}
@Test
- public void testShowAppOpsIcons_noHeader() {
+ public void testShowAppOps_noHeader() {
// public notification is custom layout - no header
mGroup.setSensitive(true, true);
- mGroup.showAppOpsIcons(new ArraySet<>());
+ mGroup.setAppOpsOnClickListener(null);
+ mGroup.showAppOpsIcons(null);
}
@Test
- public void testShowAppOpsIcons_header() throws Exception {
+ public void testShowAppOpsIcons_header() {
NotificationHeaderView mockHeader = mock(NotificationHeaderView.class);
NotificationContentView publicLayout = mock(NotificationContentView.class);
@@ -181,4 +183,16 @@
verify(publicLayout, times(1)).showAppOpsIcons(ops);
}
+
+ @Test
+ public void testAppOpsOnClick() {
+ ExpandableNotificationRow.OnAppOpsClickListener l = mock(
+ ExpandableNotificationRow.OnAppOpsClickListener.class);
+ View view = mock(View.class);
+
+ mGroup.setAppOpsOnClickListener(l);
+
+ mGroup.getAppOpsOnClickListener().onClick(view);
+ verify(l, times(1)).onClick(any(), anyInt(), anyInt(), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index 37dd939..7e5db34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -37,6 +37,8 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java
index 8f38c2c..6209d59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsManagerTest.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+
import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
@@ -34,14 +38,17 @@
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.ArraySet;
import android.view.LayoutInflater;
import android.view.View;
@@ -58,6 +65,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoRule;
import org.mockito.junit.MockitoJUnit;
@@ -164,6 +172,81 @@
verify(row, times(2)).setGutsView(any());
}
+ @Test
+ public void testAppOpsSettingsIntent_camera() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_CAMERA);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
+ }
+
+ @Test
+ public void testAppOpsSettingsIntent_mic() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_RECORD_AUDIO);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
+ }
+
+ @Test
+ public void testAppOpsSettingsIntent_camera_mic() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_CAMERA);
+ ops.add(OP_RECORD_AUDIO);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
+ }
+
+ @Test
+ public void testAppOpsSettingsIntent_overlay() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_SYSTEM_ALERT_WINDOW);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, captor.getValue().getAction());
+ }
+
+ @Test
+ public void testAppOpsSettingsIntent_camera_mic_overlay() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_CAMERA);
+ ops.add(OP_RECORD_AUDIO);
+ ops.add(OP_SYSTEM_ALERT_WINDOW);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
+ }
+
+ @Test
+ public void testAppOpsSettingsIntent_camera_overlay() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_CAMERA);
+ ops.add(OP_SYSTEM_ALERT_WINDOW);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
+ }
+
+ @Test
+ public void testAppOpsSettingsIntent_mic_overlay() {
+ ArraySet<Integer> ops = new ArraySet<>();
+ ops.add(OP_RECORD_AUDIO);
+ ops.add(OP_SYSTEM_ALERT_WINDOW);
+ mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPresenter, times(1)).startNotificationGutsIntent(captor.capture(), anyInt(), any());
+ assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////
// Utility methods:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index b8d9b19..01664b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -18,6 +18,8 @@
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
import static android.view.View.GONE;
@@ -147,6 +149,7 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
+ assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
}
@Test
@@ -213,6 +216,27 @@
}
@Test
+ public void testBindNotification_BlockButton() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ final View block = mNotificationInfo.findViewById(R.id.block);
+ final View minimize = mNotificationInfo.findViewById(R.id.minimize);
+ assertEquals(VISIBLE, block.getVisibility());
+ assertEquals(GONE, minimize.getVisibility());
+ }
+
+ @Test
+ public void testBindNotification_MinButton() throws Exception {
+ mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ final View block = mNotificationInfo.findViewById(R.id.block);
+ final View minimize = mNotificationInfo.findViewById(R.id.minimize);
+ assertEquals(GONE, block.getVisibility());
+ assertEquals(VISIBLE, minimize.getVisibility());
+ }
+
+ @Test
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -324,6 +348,18 @@
}
@Test
+ public void testDoesNotUpdateNotificationChannelAfterImportanceChangedMin()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+
+ mNotificationInfo.findViewById(R.id.minimize).performClick();
+ verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), any());
+ }
+
+ @Test
public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
throws Exception {
int originalImportance = mNotificationChannel.getImportance();
@@ -377,6 +413,39 @@
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
& USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
+ }
+
+ @Test
+ public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
+ null, Collections.singleton(TEST_PACKAGE_NAME));
+ mNotificationInfo.findViewById(R.id.minimize).performClick();
+ waitForUndoButton();
+ verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), any());
+ }
+
+ @Test
+ public void testMinChangedCallsUpdateNotificationChannel() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+
+ mNotificationInfo.findViewById(R.id.minimize).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
}
@Test
@@ -416,6 +485,40 @@
}
@Test
+ public void testMinUndoDoesNotMinNotificationChannel() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+
+ mNotificationInfo.findViewById(R.id.minimize).performClick();
+ waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.undo).performClick();
+ waitForStopButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
+ assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+ }
+
+ @Test
+ public void testCloseControlsDoesNotUpdateiMinIfSaveIsFalse() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+ Collections.singleton(TEST_PACKAGE_NAME));
+
+ mNotificationInfo.findViewById(R.id.minimize).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(false, false);
+ verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
+ }
+
+ @Test
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -557,4 +660,57 @@
public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
assertFalse(mNotificationInfo.willBeRemoved());
}
+
+ @Test
+ public void testUndoText_min() throws Exception {
+ mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+ Collections.singleton(TEST_PACKAGE_NAME));
+
+ mNotificationInfo.findViewById(R.id.minimize).performClick();
+ waitForUndoButton();
+ TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
+ assertTrue(confirmationText.getText().toString().contains("minimized"));
+ }
+
+ @Test
+ public void testUndoText_block() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+ Collections.singleton(TEST_PACKAGE_NAME));
+
+ mNotificationInfo.findViewById(R.id.block).performClick();
+ waitForUndoButton();
+ TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
+ assertTrue(confirmationText.getText().toString().contains("won't see"));
+ }
+
+ @Test
+ public void testNoHeaderOnConfirmation() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+ Collections.singleton(TEST_PACKAGE_NAME));
+
+ mNotificationInfo.findViewById(R.id.block).performClick();
+ waitForUndoButton();
+ assertEquals(GONE, mNotificationInfo.findViewById(R.id.header).getVisibility());
+ }
+
+ @Test
+ public void testHeaderOnUndo() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
+ Collections.singleton(TEST_PACKAGE_NAME));
+
+ mNotificationInfo.findViewById(R.id.block).performClick();
+ waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.undo).performClick();
+ waitForStopButton();
+ assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
index 2a2acab..2a5a1ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMenuRowTest.java
@@ -14,14 +14,23 @@
package com.android.systemui.statusbar;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
import android.testing.ViewUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -63,4 +72,19 @@
NotificationMenuRowPlugin row = new NotificationMenuRow(mContext);
row.resetMenu();
}
+
+ @Test
+ public void testNoAppOpsInSlowSwipe() {
+ NotificationMenuRow row = new NotificationMenuRow(mContext);
+ Notification n = mock(Notification.class);
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getNotification()).thenReturn(n);
+ ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+ when(parent.getStatusBarNotification()).thenReturn(sbn);
+ row.createMenu(parent, null);
+
+ ViewGroup container = (ViewGroup) row.getMenuView();
+ // one for snooze and one for noti blocking
+ assertEquals(2, container.getChildCount());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index a80b045..36fd499 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -19,6 +19,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -27,12 +28,14 @@
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -40,16 +43,15 @@
public class AutoTileManagerTest extends SysuiTestCase {
@Mock private QSTileHost mQsTileHost;
+ @Mock private AutoAddTracker mAutoAddTracker;
private AutoTileManager mAutoTileManager;
@Before
public void setUp() throws Exception {
- mDependency.injectTestDependency(Dependency.BG_LOOPER,
- TestableLooper.get(this).getLooper());
- Prefs.putBoolean(mContext, Prefs.Key.QS_NIGHTDISPLAY_ADDED, false);
- mQsTileHost = Mockito.mock(QSTileHost.class);
- mAutoTileManager = new AutoTileManager(mContext, mQsTileHost);
+ MockitoAnnotations.initMocks(this);
+ mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
+ new Handler(TestableLooper.get(this).getLooper()));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
index 500d620..667a508 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java
@@ -88,6 +88,25 @@
ev.recycle();
}
+
+ @Test
+ public void testNearestView_DetachedViewsExcluded() {
+ View left = mockViewAt(0, 0, 10, 10);
+ when(left.isAttachedToWindow()).thenReturn(false);
+ View right = mockViewAt(20, 0, 10, 10);
+
+ mNearestTouchFrame.addView(left);
+ mNearestTouchFrame.addView(right);
+ mNearestTouchFrame.onMeasure(0, 0);
+
+ // Would go to left view if attached, but goes to right instead as left should be detached.
+ MotionEvent ev = MotionEvent.obtain(0, 0, 0,
+ 12 /* x */, 5 /* y */, 0);
+ mNearestTouchFrame.onTouchEvent(ev);
+ verify(right).onTouchEvent(eq(ev));
+ ev.recycle();
+ }
+
@Test
public void testHorizontalSelection_Left() {
View left = mockViewAt(0, 0, 10, 10);
@@ -161,6 +180,7 @@
return null;
}).when(v).getLocationInWindow(any());
when(v.isClickable()).thenReturn(true);
+ when(v.isAttachedToWindow()).thenReturn(true);
// Stupid final methods.
v.setLeft(0);
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 3ed2fe1..bfa469e 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
@@ -170,12 +170,22 @@
}
@Test
- public void transitionToBouncer() {
+ public void transitionToKeyguardBouncer() {
mScrimController.transitionTo(ScrimState.BOUNCER);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be visible without tint
- assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+ assertScrimTint(mScrimBehind, false /* tinted */);
+ }
+
+ @Test
+ public void transitionToBouncer() {
+ mScrimController.transitionTo(ScrimState.BOUNCER_OCCLUDED);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible without tint
+ assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
assertScrimTint(mScrimBehind, false /* tinted */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index ff545f0..14baaeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -346,7 +346,7 @@
public void testShouldPeek_nonSuppressedGroupSummary() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
- when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
+ when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
when(mSystemServicesProxy.isDreaming()).thenReturn(false);
when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
@@ -367,7 +367,7 @@
public void testShouldPeek_suppressedGroupSummary() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
- when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
+ when(mNotificationData.shouldSuppressStatusBar(any())).thenReturn(false);
when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
when(mSystemServicesProxy.isDreaming()).thenReturn(false);
when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
@@ -385,16 +385,32 @@
}
@Test
- public void testShouldPeek_suppressedScreenOn_dozing() {
+ public void testShouldPeek_suppressedPeek() {
when(mPowerManager.isScreenOn()).thenReturn(true);
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
when(mSystemServicesProxy.isDreaming()).thenReturn(false);
when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
- mStatusBar.mDozing = true;
- when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(true);
- when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(false);
+ when(mNotificationData.shouldSuppressPeek(any())).thenReturn(true);
+
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+
+ assertFalse(mEntryManager.shouldPeek(entry, sbn));
+ }
+
+ @Test
+ public void testShouldPeek_noSuppressedPeek() {
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
+ when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
+ when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+ when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+
+ when(mNotificationData.shouldSuppressPeek(any())).thenReturn(false);
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
@@ -405,63 +421,6 @@
}
@Test
- public void testShouldPeek_suppressedScreenOn_noDoze() {
- when(mPowerManager.isScreenOn()).thenReturn(true);
- when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
- when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
- when(mSystemServicesProxy.isDreaming()).thenReturn(false);
- when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
-
- mStatusBar.mDozing = false;
- when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(true);
- when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(false);
-
- Notification n = new Notification.Builder(getContext(), "a").build();
- StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
- UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertFalse(mEntryManager.shouldPeek(entry, sbn));
- }
- @Test
- public void testShouldPeek_suppressedScreenOff_dozing() {
- when(mPowerManager.isScreenOn()).thenReturn(true);
- when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
- when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
- when(mSystemServicesProxy.isDreaming()).thenReturn(false);
- when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
-
- mStatusBar.mDozing = true;
- when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
- when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(true);
-
- Notification n = new Notification.Builder(getContext(), "a").build();
- StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
- UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertFalse(mEntryManager.shouldPeek(entry, sbn));
- }
-
- @Test
- public void testShouldPeek_suppressedScreenOff_noDoze() {
- when(mPowerManager.isScreenOn()).thenReturn(true);
- when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
- when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
- when(mSystemServicesProxy.isDreaming()).thenReturn(false);
- when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
-
- mStatusBar.mDozing = false;
- when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
- when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(true);
-
- Notification n = new Notification.Builder(getContext(), "a").build();
- StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
- UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
- assertTrue(mEntryManager.shouldPeek(entry, sbn));
- }
-
-
- @Test
public void testLogHidden() {
try {
mStatusBar.handleVisibleToUserChanged(false);
@@ -574,6 +533,7 @@
public void testFingerprintNotification_UpdatesScrims() {
mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class);
mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
+ mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
mStatusBar.notifyFpAuthModeChanged();
verify(mScrimController).transitionTo(any(), any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index e3558d4..2afb48c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -111,8 +111,8 @@
boolean out = true;
String typeDescription = "Test 1";
String description = "Test 2";
- int type = R.drawable.stat_sys_data_fully_connected_1x;
- int qsType = R.drawable.ic_qs_signal_1x;
+ int type = TelephonyIcons.ICON_1X;
+ int qsType = TelephonyIcons.ICON_1X;
boolean wide = true;
int subId = 5;
boolean roaming = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 8aab837..714ad1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@
protected static final int DEFAULT_SIGNAL_STRENGTH = DEFAULT_LEVEL;
protected static final int DEFAULT_QS_SIGNAL_STRENGTH = DEFAULT_LEVEL;
protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G;
- protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_DATA_3G;
+ protected static final int DEFAULT_QS_ICON = TelephonyIcons.ICON_3G;
protected NetworkControllerImpl mNetworkController;
protected MobileSignalController mMobileSignalController;
@@ -353,6 +353,13 @@
protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut) {
+ verifyLastMobileDataIndicators(
+ visible, icon, typeIcon, qsVisible, qsIcon, qsTypeIcon, dataIn, dataOut, false);
+ }
+
+ protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
+ boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut,
+ boolean cutOut) {
ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class);
@@ -372,7 +379,7 @@
IconState iconState = iconArg.getValue();
int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
- false);
+ cutOut);
assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
assertEquals("Signal icon in status bar", state, iconState.icon);
assertEquals("Visibility in status bar", visible, iconState.visible);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 3b796ca..8629799 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -6,7 +6,6 @@
import android.net.NetworkCapabilities;
import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -15,7 +14,6 @@
import com.android.settingslib.net.DataUsageController;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,8 +26,7 @@
public void test3gDataIcon() {
setupDefaultSignal();
- verifyDataIndicators(TelephonyIcons.ICON_3G,
- TelephonyIcons.QS_DATA_3G);
+ verifyDataIndicators(TelephonyIcons.ICON_3G);
}
@Test
@@ -38,8 +35,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_GSM);
- verifyDataIndicators(TelephonyIcons.ICON_G,
- TelephonyIcons.QS_DATA_G);
+ verifyDataIndicators(TelephonyIcons.ICON_G);
}
@Test
@@ -48,8 +44,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_CDMA);
- verifyDataIndicators(TelephonyIcons.ICON_1X,
- TelephonyIcons.QS_DATA_1X);
+ verifyDataIndicators(TelephonyIcons.ICON_1X);
}
@Test
@@ -58,8 +53,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_EDGE);
- verifyDataIndicators(TelephonyIcons.ICON_E,
- TelephonyIcons.QS_DATA_E);
+ verifyDataIndicators(TelephonyIcons.ICON_E);
}
@Test
@@ -68,8 +62,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
- verifyDataIndicators(TelephonyIcons.ICON_LTE,
- TelephonyIcons.QS_DATA_LTE);
+ verifyDataIndicators(TelephonyIcons.ICON_LTE);
}
@Test
@@ -78,8 +71,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_HSPA);
- verifyDataIndicators(TelephonyIcons.ICON_H,
- TelephonyIcons.QS_DATA_H);
+ verifyDataIndicators(TelephonyIcons.ICON_H);
}
@Test
@@ -88,7 +80,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_IWLAN);
- verifyDataIndicators(0, 0);
+ verifyDataIndicators(0);
}
@Test
@@ -106,8 +98,21 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
- verifyDataIndicators(TelephonyIcons.ICON_4G,
- TelephonyIcons.QS_DATA_4G);
+ verifyDataIndicators(TelephonyIcons.ICON_4G);
+ }
+
+ @Test
+ public void testNoInternetIcon() {
+ setupNetworkController();
+ when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
+ setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+
+ // Verify that a SignalDrawable with a cut out is used to display data disabled.
+ verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0,
+ true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false,
+ false, true);
}
@Test
@@ -118,8 +123,10 @@
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
- verifyDataIndicators(TelephonyIcons.ICON_DATA_DISABLED,
- TelephonyIcons.QS_ICON_DATA_DISABLED);
+ // Verify that a SignalDrawable with a cut out is used to display data disabled.
+ verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0,
+ true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false,
+ false, true);
}
@Test
@@ -134,7 +141,7 @@
TestableLooper.get(this).processAllMessages();
// Don't show the X until the device is setup.
- verifyDataIndicators(0, 0);
+ verifyDataIndicators(0);
}
@Test
@@ -149,8 +156,7 @@
mConfig.alwaysShowDataRatIcon = true;
mNetworkController.handleConfigurationChanged();
- verifyDataIndicators(TelephonyIcons.ICON_G,
- TelephonyIcons.QS_DATA_G);
+ verifyDataIndicators(TelephonyIcons.ICON_G);
}
@Test
@@ -166,8 +172,7 @@
// the after work.
mNetworkController.handleConfigurationChanged();
- verifyDataIndicators(TelephonyIcons.ICON_4G,
- TelephonyIcons.QS_DATA_4G);
+ verifyDataIndicators(TelephonyIcons.ICON_4G);
}
@Test
@@ -176,14 +181,12 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
- verifyDataIndicators(TelephonyIcons.ICON_LTE,
- TelephonyIcons.QS_DATA_LTE);
+ verifyDataIndicators(TelephonyIcons.ICON_LTE);
when(mServiceState.getDataNetworkType())
.thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
updateServiceState();
- verifyDataIndicators(TelephonyIcons.ICON_H,
- TelephonyIcons.QS_DATA_H);
+ verifyDataIndicators(TelephonyIcons.ICON_H);
}
@Test
@@ -203,9 +206,9 @@
DEFAULT_QS_SIGNAL_STRENGTH, DEFAULT_QS_ICON, in, out);
}
- private void verifyDataIndicators(int dataIcon, int qsDataIcon) {
+ private void verifyDataIndicators(int dataIcon) {
verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon,
- true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false,
+ true, DEFAULT_QS_SIGNAL_STRENGTH, dataIcon, false,
false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 550f4a7..33aa417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -223,7 +223,7 @@
verifyLastQsMobileDataIndicators(true,
testStrength,
- TelephonyIcons.QS_DATA_1X, false, false);
+ TelephonyIcons.ICON_1X, false, false);
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e962c0b..4be7287 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5453,6 +5453,53 @@
// OS: P
ACTION_OPS_GUTS_SETTINGS = 1346;
+ // ACTION: Settings > Battery settings > Battery tip > App restriction tip
+ // OS: P
+ ACTION_APP_RESTRICTION_TIP = 1347;
+
+ // ACTION: Settings > Battery settings > Battery tip > High usage tip
+ // OS: P
+ ACTION_HIGH_USAGE_TIP = 1348;
+
+ // ACTION: Settings > Battery settings > Battery tip > Summary tip
+ // OS: P
+ ACTION_SUMMARY_TIP = 1349;
+
+ // ACTION: Settings > Battery settings > Battery tip > Smart battery tip
+ // OS: P
+ ACTION_SMART_BATTERY_TIP = 1350;
+
+ // ACTION: Settings > Battery settings > Battery tip > Early warning tip
+ // OS: P
+ ACTION_EARLY_WARNING_TIP = 1351;
+
+ // ACTION: Settings > Battery settings > Battery tip > Low battery tip
+ // OS: P
+ ACTION_LOW_BATTERY_TIP = 1352;
+
+ // ACTION: Settings > Battery settings > Battery tip > App restriction list shown
+ // OS: P
+ ACTION_APP_RESTRICTION_TIP_LIST = 1353;
+
+ // ACTION: Settings > Battery settings > Battery tip > High usage list shown
+ // OS: P
+ ACTION_HIGH_USAGE_TIP_LIST = 1354;
+
+ // OPEN: Settings > Date & time > Select time zone -> Region
+ // CATEGORY: SETTINGS
+ // OS: P
+ SETTINGS_ZONE_PICKER_REGION = 1355;
+
+ // OPEN: Settings > Date & time > Select time zone -> Time Zone
+ // CATEGORY: SETTINGS
+ // OS: P
+ SETTINGS_ZONE_PICKER_TIME_ZONE = 1356;
+
+ // OPEN: Settings > Date & time > Select time zone -> Select UTC Offset
+ // CATEGORY: SETTINGS
+ // OS: P
+ SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
index c9d5c27..490a59e 100644
--- a/proto/src/task_snapshot.proto
+++ b/proto/src/task_snapshot.proto
@@ -27,4 +27,5 @@
int32 inset_top = 3;
int32 inset_right = 4;
int32 inset_bottom = 5;
+ bool is_real_snapshot = 6;
}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b0b9586..ecd47e8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3129,6 +3129,11 @@
boolean activeWindowGone = true;
final int windowCount = windows.size();
+
+ // We'll clear accessibility focus if the window with focus is no longer visible to
+ // accessibility services
+ boolean shouldClearAccessibilityFocus =
+ mAccessibilityFocusedWindowId != INVALID_WINDOW_ID;
if (windowCount > 0) {
for (int i = 0; i < windowCount; i++) {
WindowInfo windowInfo = windows.get(i);
@@ -3166,6 +3171,7 @@
}
if (window.getId() == mAccessibilityFocusedWindowId) {
window.setAccessibilityFocused(true);
+ shouldClearAccessibilityFocus = false;
}
}
}
@@ -3176,6 +3182,10 @@
for (int i = oldWindowCount - 1; i >= 0; i--) {
oldWindowList.remove(i).recycle();
}
+
+ if (shouldClearAccessibilityFocus) {
+ clearAccessibilityFocus(mAccessibilityFocusedWindowId);
+ }
}
private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 266b2d7..8a66414 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -59,9 +59,7 @@
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.LocalLog;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -73,6 +71,7 @@
import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.IResultReceiver;
@@ -88,8 +87,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
-import java.util.Set;
/**
* Entry point service for autofill management.
@@ -105,6 +104,9 @@
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
private static final char COMPAT_PACKAGE_DELIMITER = ':';
+ private static final char COMPAT_PACKAGE_URL_IDS_DELIMITER = ',';
+ private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
+ private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
private final Context mContext;
private final AutoFillUI mUi;
@@ -326,7 +328,7 @@
if (service == null) {
service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
- mDisabledUsers.get(resolvedUserId));
+ mAutofillCompatState, mDisabledUsers.get(resolvedUserId));
mServicesCache.put(userId, service);
addCompatibilityModeRequestsLocked(service, userId);
}
@@ -544,23 +546,24 @@
private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
, int userId) {
mAutofillCompatState.reset();
- final ArrayMap<String, Pair<Long, String>> compatPackages =
+ final ArrayMap<String, Long> compatPackages =
service.getCompatibilityPackagesLocked();
if (compatPackages == null || compatPackages.isEmpty()) {
return;
}
- final Set<String> whiteListedPackages = getWhitelistedCompatModePackages();
+
+ final Map<String, String[]> whiteListedPackages = getWhitelistedCompatModePackages();
final int compatPackageCount = compatPackages.size();
for (int i = 0; i < compatPackageCount; i++) {
final String packageName = compatPackages.keyAt(i);
- if (whiteListedPackages == null || !whiteListedPackages.contains(packageName)) {
+ if (whiteListedPackages == null || !whiteListedPackages.containsKey(packageName)) {
Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
continue;
}
- final Long maxVersionCode = compatPackages.valueAt(i).first;
+ final Long maxVersionCode = compatPackages.valueAt(i);
if (maxVersionCode != null) {
mAutofillCompatState.addCompatibilityModeRequest(packageName,
- maxVersionCode, userId);
+ maxVersionCode, whiteListedPackages.get(packageName), userId);
}
}
}
@@ -571,16 +574,60 @@
Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
}
- private @Nullable Set<String> getWhitelistedCompatModePackages() {
- final String compatPackagesSetting = getWhitelistedCompatModePackagesFromSettings();
- if (TextUtils.isEmpty(compatPackagesSetting)) {
+ @Nullable
+ private Map<String, String[]> getWhitelistedCompatModePackages() {
+ return getWhitelistedCompatModePackages(getWhitelistedCompatModePackagesFromSettings());
+ }
+
+ @Nullable
+ @VisibleForTesting
+ static Map<String, String[]> getWhitelistedCompatModePackages(String setting) {
+ if (TextUtils.isEmpty(setting)) {
return null;
}
- final Set<String> compatPackages = new ArraySet<>();
+
+ final ArrayMap<String, String[]> compatPackages = new ArrayMap<>();
final SimpleStringSplitter splitter = new SimpleStringSplitter(COMPAT_PACKAGE_DELIMITER);
- splitter.setString(compatPackagesSetting);
+ splitter.setString(setting);
while (splitter.hasNext()) {
- compatPackages.add(splitter.next());
+ final String packageBlock = splitter.next();
+ final int urlBlockIndex = packageBlock.indexOf(COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN);
+ final String packageName;
+ final List<String> urlBarIds;
+ if (urlBlockIndex == -1) {
+ packageName = packageBlock;
+ urlBarIds = null;
+ } else {
+ if (packageBlock.charAt(packageBlock.length() - 1)
+ != COMPAT_PACKAGE_URL_IDS_BLOCK_END) {
+ Slog.w(TAG, "Ignoring entry '" + packageBlock + "' on '" + setting
+ + "'because it does not end on '" + COMPAT_PACKAGE_URL_IDS_BLOCK_END +
+ "'");
+ continue;
+ }
+ packageName = packageBlock.substring(0, urlBlockIndex);
+ urlBarIds = new ArrayList<>();
+ final String urlBarIdsBlock =
+ packageBlock.substring(urlBlockIndex + 1, packageBlock.length() - 1);
+ if (sVerbose) {
+ Slog.v(TAG, "pkg:" + packageName + ": block:" + packageBlock + ": urls:"
+ + urlBarIds + ": block:" + urlBarIdsBlock + ":");
+ }
+ final SimpleStringSplitter splitter2 =
+ new SimpleStringSplitter(COMPAT_PACKAGE_URL_IDS_DELIMITER);
+ splitter2.setString(urlBarIdsBlock);
+ while (splitter2.hasNext()) {
+ final String urlBarId = splitter2.next();
+ urlBarIds.add(urlBarId);
+ }
+ }
+ if (urlBarIds == null) {
+ compatPackages.put(packageName, null);
+ } else {
+ final String[] urlBarIdsArray = new String[urlBarIds.size()];
+ urlBarIds.toArray(urlBarIdsArray);
+ compatPackages.put(packageName, urlBarIdsArray);
+ }
}
return compatPackages;
}
@@ -598,13 +645,41 @@
return mAutofillCompatState.isCompatibilityModeRequested(
packageName, versionCode, userId);
}
+
}
- private static final class AutofillCompatState {
+ /**
+ * Compatibility mode metadata per package.
+ */
+ private static final class PackageCompatState {
+ private final long maxVersionCode;
+ private final String[] urlBarResourceIds;
+
+ PackageCompatState(long maxVersionCode, String[] urlBarResourceIds) {
+ this.maxVersionCode = maxVersionCode;
+ this.urlBarResourceIds = urlBarResourceIds;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageCompatState: [maxVersionCode=" + maxVersionCode
+ + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds) + "]";
+ }
+ }
+
+ /**
+ * Compatibility mode metadata associated with all services.
+ *
+ * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
+ * it cannot hold a lock on the main lock when
+ * {@link AutofillCompatState#isCompatibilityModeRequested(String, long, int)} is called by
+ * external services.
+ */
+ static final class AutofillCompatState {
private final Object mLock = new Object();
@GuardedBy("mLock")
- private SparseArray<ArrayMap<String, Long>> mUserSpecs;
+ private SparseArray<ArrayMap<String, PackageCompatState>> mUserSpecs;
boolean isCompatibilityModeRequested(@NonNull String packageName,
long versionCode, @UserIdInt int userId) {
@@ -612,30 +687,49 @@
if (mUserSpecs == null) {
return false;
}
- final ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ final ArrayMap<String, PackageCompatState> userSpec = mUserSpecs.get(userId);
if (userSpec == null) {
return false;
}
- final Long maxVersionCode = userSpec.get(packageName);
- if (maxVersionCode == null) {
+ final PackageCompatState metadata = userSpec.get(packageName);
+ if (metadata == null) {
return false;
}
- return versionCode <= maxVersionCode;
+ return versionCode <= metadata.maxVersionCode;
+ }
+ }
+
+ @Nullable
+ String[] getUrlBarResourceIds(@NonNull String packageName, @UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs == null) {
+ return null;
+ }
+ final ArrayMap<String, PackageCompatState> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ return null;
+ }
+ final PackageCompatState metadata = userSpec.get(packageName);
+ if (metadata == null) {
+ return null;
+ }
+ return metadata.urlBarResourceIds;
}
}
void addCompatibilityModeRequest(@NonNull String packageName,
- long versionCode, @UserIdInt int userId) {
+ long versionCode, @Nullable String[] urlBarResourceIds, @UserIdInt int userId) {
synchronized (mLock) {
if (mUserSpecs == null) {
mUserSpecs = new SparseArray<>();
}
- ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ ArrayMap<String, PackageCompatState> userSpec = mUserSpecs.get(userId);
if (userSpec == null) {
userSpec = new ArrayMap<>();
mUserSpecs.put(userId, userSpec);
}
- userSpec.put(packageName, versionCode);
+ userSpec.put(packageName,
+ new PackageCompatState(versionCode, urlBarResourceIds));
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8622dbe..54ea3ba 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -64,7 +64,6 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -78,12 +77,12 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
+import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.Random;
/**
@@ -164,12 +163,15 @@
@GuardedBy("mLock")
private FillEventHistory mEventHistory;
+ /** Shared instance, doesn't need to be logged */
+ private final AutofillCompatState mAutofillCompatState;
+
/** When was {@link PruneTask} last executed? */
private long mLastPrune = 0;
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
- boolean disabled) {
+ AutofillCompatState autofillCompatState, boolean disabled) {
mContext = context;
mLock = lock;
mRequestsHistory = requestsHistory;
@@ -178,6 +180,7 @@
mUserId = userId;
mUi = ui;
mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId);
+ mAutofillCompatState = autofillCompatState;
updateLocked(disabled);
}
@@ -208,14 +211,9 @@
}
- @GuardedBy("mLock")
@Nullable
- String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) {
- if (mInfo == null) {
- Slog.w(TAG, "getUrlBarResourceIdForCompatModeLocked(): no mInfo");
- return null;
- }
- return mInfo.getUrlBarResourceId(packageName);
+ String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
+ return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
}
@Nullable
@@ -893,7 +891,7 @@
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
pw.print(prefix); pw.print("Compat pkgs: ");
- final ArrayMap<String, Pair<Long, String>> compatPkgs = getCompatibilityPackagesLocked();
+ final ArrayMap<String, Long> compatPkgs = getCompatibilityPackagesLocked();
if (compatPkgs == null) {
pw.println("N/A");
} else {
@@ -1022,7 +1020,7 @@
}
@GuardedBy("mLock")
- @Nullable ArrayMap<String, Pair<Long, String>> getCompatibilityPackagesLocked() {
+ @Nullable ArrayMap<String, Long> getCompatibilityPackagesLocked() {
if (mInfo != null) {
return mInfo.getCompatibilityPackages();
}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 232dfdc..5c41f3f 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -30,6 +30,7 @@
import android.view.autofill.AutofillValue;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -168,21 +169,24 @@
/**
* Sanitize the {@code webDomain} property of the URL bar node on compat mode.
+ *
+ * @param structure Assist structure
+ * @param urlBarIds list of ids; only the first id found will be sanitized.
*/
public static void sanitizeUrlBar(@NonNull AssistStructure structure,
- @NonNull String urlBarId) {
+ @NonNull String[] urlBarIds) {
final ViewNode urlBarNode = findViewNode(structure, (node) -> {
- return urlBarId.equals(node.getIdEntry());
+ return ArrayUtils.contains(urlBarIds, node.getIdEntry());
});
if (urlBarNode != null) {
final String domain = urlBarNode.getText().toString();
if (domain.isEmpty()) {
- if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId);
+ if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarNode.getIdEntry());
return;
}
urlBarNode.setWebDomain(domain);
if (sDebug) {
- Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain="
+ Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarNode.getIdEntry() + ", domain="
+ urlBarNode.getWebDomain());
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5eee9ed..26598a2 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -254,7 +254,7 @@
// change AssistStructure so it provides a "one-way" writeToParcel() method that
// sends all the data
try {
- structure.ensureData();
+ structure.ensureDataForAutofill();
} catch (RuntimeException e) {
wtf(e, "Exception lazy loading assist structure for %s: %s",
structure.getActivityComponent(), e);
@@ -274,11 +274,13 @@
}
if (mCompatMode) {
// Sanitize URL bar, if needed
- final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked(
+ final String[] urlBarIds = mService.getUrlBarResourceIdsForCompatMode(
mComponentName.getPackageName());
- if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId);
- if (urlBarId != null) {
- Helper.sanitizeUrlBar(structure, urlBarId);
+ if (sDebug) {
+ Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
+ }
+ if (urlBarIds != null) {
+ Helper.sanitizeUrlBar(structure, urlBarIds);
}
}
structure.sanitizeForParceling(true);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 369df54..6469091 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3525,7 +3525,10 @@
dumpAgents(pw);
return;
} else if ("transportclients".equals(arg.toLowerCase())) {
- mTransportManager.dump(pw);
+ mTransportManager.dumpTransportClients(pw);
+ return;
+ } else if ("transportstats".equals(arg.toLowerCase())) {
+ mTransportManager.dumpTransportStats(pw);
return;
}
}
@@ -3590,7 +3593,7 @@
}
}
- mTransportManager.dump(pw);
+ mTransportManager.dumpTransportClients(pw);
pw.println("Pending init: " + mPendingInits.size());
for (String s : mPendingInits) {
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index c87d298..6a1bf17 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -44,6 +44,7 @@
import com.android.server.backup.transport.TransportConnectionListener;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
+import com.android.server.backup.transport.TransportStats;
import java.io.PrintWriter;
import java.util.List;
@@ -64,6 +65,7 @@
private final PackageManager mPackageManager;
private final Set<ComponentName> mTransportWhitelist;
private final TransportClientManager mTransportClientManager;
+ private final TransportStats mTransportStats;
private OnTransportRegisteredListener mOnTransportRegisteredListener = (c, n) -> {};
/**
@@ -85,7 +87,12 @@
private volatile String mCurrentTransportName;
TransportManager(Context context, Set<ComponentName> whitelist, String selectedTransport) {
- this(context, whitelist, selectedTransport, new TransportClientManager(context));
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ mTransportWhitelist = Preconditions.checkNotNull(whitelist);
+ mCurrentTransportName = selectedTransport;
+ mTransportStats = new TransportStats();
+ mTransportClientManager = new TransportClientManager(context, mTransportStats);
}
@VisibleForTesting
@@ -98,6 +105,7 @@
mPackageManager = context.getPackageManager();
mTransportWhitelist = Preconditions.checkNotNull(whitelist);
mCurrentTransportName = selectedTransport;
+ mTransportStats = new TransportStats();
mTransportClientManager = transportClientManager;
}
@@ -640,10 +648,14 @@
!Thread.holdsLock(mTransportLock), "Can't call transport with transport lock held");
}
- public void dump(PrintWriter pw) {
+ public void dumpTransportClients(PrintWriter pw) {
mTransportClientManager.dump(pw);
}
+ public void dumpTransportStats(PrintWriter pw) {
+ mTransportStats.dump(pw);
+ }
+
private static Predicate<ComponentName> fromPackageFilter(String packageName) {
return transportComponent -> packageName.equals(transportComponent.getPackageName());
}
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 1a2ca92..fa881a9 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -29,6 +29,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
@@ -51,6 +52,7 @@
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -78,6 +80,7 @@
private static final int LOG_BUFFER_SIZE = 5;
private final Context mContext;
+ private final TransportStats mTransportStats;
private final Intent mBindIntent;
private final ServiceConnection mConnection;
private final String mIdentifier;
@@ -104,12 +107,14 @@
TransportClient(
Context context,
+ TransportStats transportStats,
Intent bindIntent,
ComponentName transportComponent,
String identifier,
String caller) {
this(
context,
+ transportStats,
bindIntent,
transportComponent,
identifier,
@@ -120,12 +125,14 @@
@VisibleForTesting
TransportClient(
Context context,
+ TransportStats transportStats,
Intent bindIntent,
ComponentName transportComponent,
String identifier,
String caller,
Handler listenerHandler) {
mContext = context;
+ mTransportStats = transportStats;
mTransportComponent = transportComponent;
mBindIntent = bindIntent;
mIdentifier = identifier;
@@ -321,11 +328,16 @@
(requestedTransport, transportClient) ->
transportFuture.complete(requestedTransport);
+ long requestTime = SystemClock.elapsedRealtime();
log(Priority.DEBUG, caller, "Sync connect: calling async");
connectAsync(requestListener, caller);
try {
- return transportFuture.get();
+ transport = transportFuture.get();
+ long time = SystemClock.elapsedRealtime() - requestTime;
+ mTransportStats.registerConnectionTime(mTransportComponent, time);
+ log(Priority.DEBUG, caller, String.format(Locale.US, "Connect took %d ms", time));
+ return transport;
} catch (InterruptedException | ExecutionException e) {
String error = e.getClass().getSimpleName();
log(Priority.ERROR, caller, error + " while waiting for transport: " + e.getMessage());
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 96e7d2f..f4e3928 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -37,12 +37,14 @@
private static final String TAG = "TransportClientManager";
private final Context mContext;
+ private final TransportStats mTransportStats;
private final Object mTransportClientsLock = new Object();
private int mTransportClientsCreated = 0;
private Map<TransportClient, String> mTransportClientsCallerMap = new WeakHashMap<>();
- public TransportClientManager(Context context) {
+ public TransportClientManager(Context context, TransportStats transportStats) {
mContext = context;
+ mTransportStats = transportStats;
}
/**
@@ -88,6 +90,7 @@
TransportClient transportClient =
new TransportClient(
mContext,
+ mTransportStats,
bindIntent,
transportComponent,
Integer.toString(mTransportClientsCreated),
diff --git a/services/backup/java/com/android/server/backup/transport/TransportStats.java b/services/backup/java/com/android/server/backup/transport/TransportStats.java
new file mode 100644
index 0000000..4bef81a
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/transport/TransportStats.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 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.backup.transport;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+/** Responsible for aggregating {@link TransportClient} relevant times. */
+public class TransportStats {
+ private final Object mStatsLock = new Object();
+ private final Map<ComponentName, Stats> mTransportStats = new HashMap<>();
+
+ void registerConnectionTime(ComponentName transportComponent, long timeMs) {
+ synchronized (mStatsLock) {
+ mTransportStats
+ .computeIfAbsent(transportComponent, name -> new Stats())
+ .register(timeMs);
+ }
+ }
+
+ /** Returns {@link Stats} for transport whose host service is {@code transportComponent}. */
+ @Nullable
+ public Stats getStatsForTransport(ComponentName transportComponent) {
+ synchronized (mStatsLock) {
+ Stats stats = mTransportStats.get(transportComponent);
+ if (stats == null) {
+ return null;
+ }
+ return new Stats(stats);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ synchronized (mStatsLock) {
+ Optional<Stats> aggregatedStats =
+ mTransportStats.values().stream().reduce(Stats::merge);
+ if (aggregatedStats.isPresent()) {
+ dumpStats(pw, "", aggregatedStats.get());
+ }
+ if (!mTransportStats.isEmpty()) {
+ pw.println("Per transport:");
+ for (ComponentName transportComponent : mTransportStats.keySet()) {
+ Stats stats = mTransportStats.get(transportComponent);
+ pw.println(" " + transportComponent.flattenToShortString());
+ dumpStats(pw, " ", stats);
+ }
+ }
+ }
+ }
+
+ private static void dumpStats(PrintWriter pw, String prefix, Stats stats) {
+ pw.println(
+ String.format(
+ Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.mAverage));
+ pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.mMax));
+ pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.mMin));
+ pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.mN));
+ }
+
+ public static final class Stats {
+ public static Stats merge(Stats a, Stats b) {
+ return new Stats(
+ a.mN + b.mN,
+ (a.mAverage * a.mN + b.mAverage * b.mN) / (a.mN + b.mN),
+ Math.max(a.mMax, b.mMax),
+ Math.min(a.mMin, b.mMin));
+ }
+
+ public int mN;
+ public double mAverage;
+ public long mMax;
+ public long mMin;
+
+ public Stats() {
+ mN = 0;
+ mAverage = 0;
+ mMax = 0;
+ mMin = Long.MAX_VALUE;
+ }
+
+ private Stats(Stats original) {
+ mN = original.mN;
+ mAverage = original.mAverage;
+ mMax = original.mMax;
+ mMin = original.mMin;
+ }
+
+ private Stats(int n, double average, long max, long min) {
+ mN = n;
+ mAverage = average;
+ mMax = max;
+ mMin = min;
+ }
+
+ private void register(long sample) {
+ mAverage = (mAverage * mN + sample) / (mN + 1);
+ mN++;
+ mMax = Math.max(mMax, sample);
+ mMin = Math.min(mMin, sample);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index d066056..8ce4e64 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1868,6 +1868,7 @@
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapsedRealtime();
+ final long nowUPTIME = SystemClock.uptimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
pw.print(" nowRTC="); pw.print(nowRTC);
@@ -1883,6 +1884,25 @@
pw.print(" mLastTickSet="); pw.println(sdf.format(new Date(mLastTickSet)));
pw.print(" mLastTickAdded="); pw.println(sdf.format(new Date(mLastTickAdded)));
pw.print(" mLastTickRemoved="); pw.println(sdf.format(new Date(mLastTickRemoved)));
+
+ SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class);
+ if (ssm != null) {
+ pw.println();
+ pw.print(" RuntimeStarted=");
+ pw.print(sdf.format(
+ new Date(nowRTC - nowELAPSED + ssm.getRuntimeStartElapsedTime())));
+ if (ssm.isRuntimeRestarted()) {
+ pw.print(" (Runtime restarted)");
+ }
+ pw.println();
+ pw.print(" Runtime uptime (elapsed): ");
+ TimeUtils.formatDuration(nowELAPSED, ssm.getRuntimeStartElapsedTime(), pw);
+ pw.println();
+ pw.print(" Runtime uptime (uptime): ");
+ TimeUtils.formatDuration(nowUPTIME, ssm.getRuntimeStartUptime(), pw);
+ pw.println();
+ }
+
pw.println();
if (!mInteractive) {
pw.print(" Time since non-interactive: ");
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index a6b71b7..16be680 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -258,7 +258,7 @@
*/
private void onRunAnyAppOpsChanged(AppStateTracker sender,
int uid, @NonNull String packageName) {
- updateJobsForUidPackage(uid, packageName);
+ updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid));
if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ false)) {
unblockAlarmsForUidPackage(uid, packageName);
@@ -279,9 +279,11 @@
* This is called when the active/idle state changed for a UID.
*/
private void onUidActiveStateChanged(AppStateTracker sender, int uid) {
- updateJobsForUid(uid);
+ final boolean isActive = sender.isUidActive(uid);
- if (sender.isUidActive(uid)) {
+ updateJobsForUid(uid, isActive);
+
+ if (isActive) {
unblockAlarmsForUid(uid);
}
}
@@ -346,14 +348,14 @@
* Called when the job restrictions for a UID might have changed, so the job
* scheduler should re-evaluate all restrictions for all jobs.
*/
- public void updateJobsForUid(int uid) {
+ public void updateJobsForUid(int uid, boolean isNowActive) {
}
/**
* Called when the job restrictions for a UID - package might have changed, so the job
* scheduler should re-evaluate all restrictions for all jobs.
*/
- public void updateJobsForUidPackage(int uid, String packageName) {
+ public void updateJobsForUidPackage(int uid, String packageName, boolean isNowActive) {
}
/**
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 8265262..d31a605 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -20,6 +20,7 @@
import android.database.ContentObserver;
import android.os.BatteryStats;
+import android.os.Bundle;
import android.os.PowerManager;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -35,7 +36,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
import android.hardware.health.V1_0.HealthInfo;
@@ -73,6 +73,8 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
@@ -117,6 +119,8 @@
private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
private static final long HEALTH_HAL_WAIT_MS = 1000;
+ private static final long BATTERY_LEVEL_CHANGE_THROTTLE_MS = 60_000;
+ private static final int MAX_BATTERY_LEVELS_QUEUE_SIZE = 100;
// Used locally for determining when to make a last ditch effort to log
// discharge stats before the device dies.
@@ -178,7 +182,8 @@
private HealthServiceWrapper mHealthServiceWrapper;
private HealthHalCallback mHealthHalCallback;
private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
- private HandlerThread mHandlerThread;
+ private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
+ private long mLastBatteryLevelChangedSentMs;
public BatteryService(Context context) {
super(context);
@@ -198,6 +203,8 @@
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shutdownBatteryTemperature);
+ mBatteryLevelsEventQueue = new ArrayDeque<>();
+
// watch for invalid charger messages if the invalid_charger switch exists
if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
UEventObserver invalidChargerObserver = new UEventObserver() {
@@ -585,7 +592,11 @@
// We are doing this after sending the above broadcasts, so anything processing
// them will get the new sequence number at that point. (See for example how testing
// of JobScheduler's BatteryController works.)
- sendIntentLocked();
+ sendBatteryChangedIntentLocked();
+ if (mLastBatteryLevel != mHealthInfo.batteryLevel) {
+ sendBatteryLevelChangedIntentLocked();
+ }
+
// Update the battery LED
mLed.updateLightsLocked();
@@ -610,7 +621,7 @@
}
}
- private void sendIntentLocked() {
+ private void sendBatteryChangedIntentLocked() {
// Pack up the values and broadcast them to everyone
final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -639,12 +650,51 @@
+ ", info:" + mHealthInfo.toString());
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
- }
- });
+ mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL));
+ }
+
+ private void sendBatteryLevelChangedIntentLocked() {
+ Bundle event = new Bundle();
+ long now = SystemClock.elapsedRealtime();
+ event.putInt(BatteryManager.EXTRA_SEQUENCE, mSequence);
+ event.putInt(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
+ event.putInt(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
+ event.putBoolean(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
+ event.putInt(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
+ event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
+ event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
+ event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
+ event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
+ event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
+
+ boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
+ mBatteryLevelsEventQueue.add(event);
+ // Make sure queue is bounded and doesn't exceed intent payload limits
+ if (mBatteryLevelsEventQueue.size() > MAX_BATTERY_LEVELS_QUEUE_SIZE) {
+ mBatteryLevelsEventQueue.removeFirst();
+ }
+
+ if (queueWasEmpty) {
+ // send now if last event was before throttle interval, otherwise delay
+ long delay = now - mLastBatteryLevelChangedSentMs > BATTERY_LEVEL_CHANGE_THROTTLE_MS
+ ? 0 : mLastBatteryLevelChangedSentMs + BATTERY_LEVEL_CHANGE_THROTTLE_MS - now;
+ mHandler.postDelayed(this::sendEnqueuedBatteryLevelChangedEvents, delay);
+ }
+ }
+
+ private void sendEnqueuedBatteryLevelChangedEvents() {
+ ArrayList<Bundle> events;
+ synchronized (mLock) {
+ events = new ArrayList<>(mBatteryLevelsEventQueue);
+ mBatteryLevelsEventQueue.clear();
+ }
+ final Intent intent = new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ intent.putParcelableArrayListExtra(BatteryManager.EXTRA_EVENTS, events);
+
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.BATTERY_STATS);
+ mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
}
private void logBatteryStatsLocked() {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 55ad8cc..02b1380 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -21,6 +21,7 @@
import android.app.AppGlobals;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothGatt;
@@ -87,14 +88,6 @@
private static final int ACTIVE_LOG_MAX_SIZE = 20;
private static final int CRASH_LOG_MAX_SIZE = 100;
- private static final String REASON_AIRPLANE_MODE = "airplane mode";
- private static final String REASON_DISALLOWED = "disallowed by system";
- private static final String REASON_RESTARTED = "automatic restart";
- private static final String REASON_START_CRASH = "turn-on crash";
- private static final String REASON_SYSTEM_BOOT = "system boot";
- private static final String REASON_UNEXPECTED = "unexpected crash";
- private static final String REASON_USER_SWITCH = "user switch";
- private static final String REASON_RESTORE_USER_SETTING = "restore user setting";
private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
//Maximum msec to wait for service restart
@@ -163,7 +156,7 @@
private boolean mQuietEnable = false;
private boolean mEnable;
- private CharSequence timeToLog(long timestamp) {
+ private static CharSequence timeToLog(long timestamp) {
return android.text.format.DateFormat.format("MM-dd HH:mm:ss", timestamp);
}
@@ -171,29 +164,27 @@
* Used for tracking apps that enabled / disabled Bluetooth.
*/
private class ActiveLog {
+ private int mReason;
private String mPackageName;
private boolean mEnable;
private long mTimestamp;
- ActiveLog(String packageName, boolean enable, long timestamp) {
+ ActiveLog(int reason, String packageName, boolean enable, long timestamp) {
+ mReason = reason;
mPackageName = packageName;
mEnable = enable;
mTimestamp = timestamp;
}
- public long getTime() {
- return mTimestamp;
- }
-
public String toString() {
- return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ") + " by "
- + mPackageName;
+ return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ")
+ + " due to " + getEnableDisableReasonString(mReason) + " by " + mPackageName;
}
}
- private LinkedList<ActiveLog> mActiveLogs;
- private LinkedList<Long> mCrashTimestamps;
+ private final LinkedList<ActiveLog> mActiveLogs = new LinkedList<>();
+ private final LinkedList<Long> mCrashTimestamps = new LinkedList<>();
private int mCrashes;
private long mLastEnabledTime;
@@ -213,8 +204,7 @@
// Save a ProfileServiceConnections object for each of the bound
// bluetooth profile services
- private final Map<Integer, ProfileServiceConnections> mProfileServices =
- new HashMap<Integer, ProfileServiceConnections>();
+ private final Map<Integer, ProfileServiceConnections> mProfileServices = new HashMap<>();
private final boolean mPermissionReviewRequired;
@@ -246,7 +236,8 @@
if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean(
UserManager.DISALLOW_BLUETOOTH)) {
updateOppLauncherComponentState(userId, true); // Sharing disallowed
- sendDisableMsg(REASON_DISALLOWED);
+ sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED,
+ mContext.getPackageName());
} else {
updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
UserManager.DISALLOW_BLUETOOTH_SHARING));
@@ -303,10 +294,13 @@
mBluetoothLock.readLock().unlock();
}
} else if (st == BluetoothAdapter.STATE_ON) {
- sendDisableMsg(REASON_AIRPLANE_MODE);
+ sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
+ mContext.getPackageName());
}
} else if (mEnableExternal) {
- sendEnableMsg(mQuietEnableExternal, REASON_AIRPLANE_MODE);
+ sendEnableMsg(mQuietEnableExternal,
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
+ mContext.getPackageName());
}
}
}
@@ -369,8 +363,6 @@
mPermissionReviewRequired = context.getResources()
.getBoolean(com.android.internal.R.bool.config_permissionReviewRequired);
- mActiveLogs = new LinkedList<ActiveLog>();
- mCrashTimestamps = new LinkedList<Long>();
mCrashes = 0;
mBluetooth = null;
mBluetoothBinder = null;
@@ -671,8 +663,8 @@
return false;
}
try {
- return (Settings.Global.getInt(mContentResolver,
- Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
+ return Settings.Global.getInt(mContentResolver,
+ Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE) != 0;
} catch (SettingNotFoundException e) {
}
return false;
@@ -867,7 +859,8 @@
synchronized (mReceiver) {
mQuietEnableExternal = true;
mEnableExternal = true;
- sendEnableMsg(true, packageName);
+ sendEnableMsg(true,
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
}
return true;
}
@@ -907,7 +900,8 @@
mQuietEnableExternal = false;
mEnableExternal = true;
// waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false, packageName);
+ sendEnableMsg(false,
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
}
if (DBG) {
Slog.d(TAG, "enable returning");
@@ -943,7 +937,8 @@
persistBluetoothSetting(BLUETOOTH_OFF);
}
mEnableExternal = false;
- sendDisableMsg(packageName);
+ sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
+ packageName);
}
return true;
}
@@ -1127,7 +1122,9 @@
if (DBG) {
Slog.d(TAG, "Auto-enabling Bluetooth.");
}
- sendEnableMsg(mQuietEnableExternal, REASON_SYSTEM_BOOT);
+ sendEnableMsg(mQuietEnableExternal,
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,
+ mContext.getPackageName());
} else if (!isNameAndAddressSet()) {
if (DBG) {
Slog.d(TAG, "Getting adapter name and address");
@@ -1569,20 +1566,25 @@
break;
case MESSAGE_RESTORE_USER_SETTING:
- try {
- if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
- if (DBG) {
- Slog.d(TAG, "Restore Bluetooth state to disabled");
- }
- disable(REASON_RESTORE_USER_SETTING, true);
- } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) {
- if (DBG) {
- Slog.d(TAG, "Restore Bluetooth state to enabled");
- }
- enable(REASON_RESTORE_USER_SETTING);
+ if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
+ if (DBG) {
+ Slog.d(TAG, "Restore Bluetooth state to disabled");
}
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to change Bluetooth On setting", e);
+ persistBluetoothSetting(BLUETOOTH_OFF);
+ mEnableExternal = false;
+ sendDisableMsg(
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING,
+ mContext.getPackageName());
+ } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) {
+ if (DBG) {
+ Slog.d(TAG, "Restore Bluetooth state to enabled");
+ }
+ mQuietEnableExternal = false;
+ mEnableExternal = true;
+ // waive WRITE_SECURE_SETTINGS permission check
+ sendEnableMsg(false,
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING,
+ mContext.getPackageName());
}
break;
@@ -1609,7 +1611,7 @@
break;
}
case MESSAGE_ADD_PROXY_DELAYED: {
- ProfileServiceConnections psc = mProfileServices.get(new Integer(msg.arg1));
+ ProfileServiceConnections psc = mProfileServices.get(msg.arg1);
if (psc == null) {
break;
}
@@ -1758,7 +1760,8 @@
// log the unexpected crash
addCrashLog();
- addActiveLog(REASON_UNEXPECTED, false);
+ addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH,
+ mContext.getPackageName(), false);
if (mEnable) {
mEnable = false;
// Send a Bluetooth Restart message
@@ -1792,7 +1795,8 @@
it doesnt change when IBluetooth
service restarts */
mEnable = true;
- addActiveLog(REASON_RESTARTED, true);
+ addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED,
+ mContext.getPackageName(), true);
handleEnable(mQuietEnable);
break;
}
@@ -1848,7 +1852,8 @@
unbindAllBluetoothProfileServices();
// disable
- addActiveLog(REASON_USER_SWITCH, false);
+ addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH,
+ mContext.getPackageName(), false);
handleDisable();
// Pbap service need receive STATE_TURNING_OFF intent to close
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
@@ -1886,7 +1891,8 @@
mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
// enable
- addActiveLog(REASON_USER_SWITCH, true);
+ addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH,
+ mContext.getPackageName(), true);
// mEnable flag could have been reset on disableBLE. Reenable it.
mEnable = true;
handleEnable(mQuietEnable);
@@ -2153,23 +2159,24 @@
return false;
}
- private void sendDisableMsg(String packageName) {
+ private void sendDisableMsg(int reason, String packageName) {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
- addActiveLog(packageName, false);
+ addActiveLog(reason, packageName, false);
}
- private void sendEnableMsg(boolean quietMode, String packageName) {
+ private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
- addActiveLog(packageName, true);
+ addActiveLog(reason, packageName, true);
mLastEnabledTime = SystemClock.elapsedRealtime();
}
- private void addActiveLog(String packageName, boolean enable) {
+ private void addActiveLog(int reason, String packageName, boolean enable) {
synchronized (mActiveLogs) {
if (mActiveLogs.size() > ACTIVE_LOG_MAX_SIZE) {
mActiveLogs.remove();
}
- mActiveLogs.add(new ActiveLog(packageName, enable, System.currentTimeMillis()));
+ mActiveLogs.add(
+ new ActiveLog(reason, packageName, enable, System.currentTimeMillis()));
}
}
@@ -2200,7 +2207,8 @@
SystemClock.sleep(500);
// disable
- addActiveLog(REASON_START_CRASH, false);
+ addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR,
+ mContext.getPackageName(), false);
handleDisable();
waitForOnOff(false, true);
@@ -2344,4 +2352,29 @@
writer.println(errorMsg);
}
}
+
+ private static String getEnableDisableReasonString(int reason) {
+ switch (reason) {
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST:
+ return "APPLICATION_REQUEST";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE:
+ return "AIRPLANE_MODE";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED:
+ return "DISALLOWED";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED:
+ return "RESTARTED";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR:
+ return "START_ERROR";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT:
+ return "SYSTEM_BOOT";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH:
+ return "CRASH";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH:
+ return "USER_SWITCH";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING:
+ return "RESTORE_USER_SETTING";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED:
+ default: return "UNKNOWN[" + reason + "]";
+ }
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 79297aa..30d31b8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1705,6 +1705,7 @@
ni != null ? ni.getState().toString() : "?");
} catch (RemoteException e) {
}
+ intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 0502117..45c9a71 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -35,6 +35,8 @@
# Power save state has changed. See BatterySaverController.java for the details.
2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5)
27390 battery_saving_stats (batterySaver|1|5),(interactive|1|5),(doze|1|5),(delta_duration|2|3),(delta_battery_drain|1|1),(delta_battery_drain_percent|1|6),(total_duration|2|3),(total_battery_drain|1|1),(total_battery_drain_percent|1|6)
+# Note when the user activity timeout has been overriden by ActivityManagerService
+27391 user_activity_timeout_override (override|2|3)
#
# Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 70ca161..5b57c14 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -92,7 +92,6 @@
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
-import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -2490,16 +2489,6 @@
}
}
- private void notifyInputMethodSubtypeChanged(final int userId,
- @Nullable final InputMethodInfo inputMethodInfo,
- @Nullable final InputMethodSubtype subtype) {
- final InputManagerInternal inputManagerInternal =
- LocalServices.getService(InputManagerInternal.class);
- if (inputManagerInternal != null) {
- inputManagerInternal.onInputMethodSubtypeChanged(userId, inputMethodInfo, subtype);
- }
- }
-
/* package */ void setInputMethodLocked(String id, int subtypeId) {
InputMethodInfo info = mMethodMap.get(id);
if (info == null) {
@@ -2534,10 +2523,8 @@
mCurMethod.changeInputMethodSubtype(newSubtype);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call changeInputMethodSubtype");
- return;
}
}
- notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info, newSubtype);
}
return;
}
@@ -2563,9 +2550,6 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info,
- getCurrentInputMethodSubtypeLocked());
}
@Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 88ae224..af4c1a0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1789,6 +1789,8 @@
@Override
public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
throws ServiceSpecificException {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+
try {
mNetdService.networkRejectNonSecureVpn(add, uidRanges);
} catch (ServiceSpecificException e) {
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 581914d..63584d9 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -39,6 +39,8 @@
private final Context mContext;
private boolean mSafeMode;
private boolean mRuntimeRestarted;
+ private long mRuntimeStartElapsedTime;
+ private long mRuntimeStartUptime;
// Services that should receive lifecycle events.
private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
@@ -287,8 +289,25 @@
return mRuntimeRestarted;
}
- void setRuntimeRestarted(boolean runtimeRestarted) {
+ /**
+ * @return Time when SystemServer was started, in elapsed realtime.
+ */
+ public long getRuntimeStartElapsedTime() {
+ return mRuntimeStartElapsedTime;
+ }
+
+ /**
+ * @return Time when SystemServer was started, in uptime.
+ */
+ public long getRuntimeStartUptime() {
+ return mRuntimeStartUptime;
+ }
+
+ void setStartInfo(boolean runtimeRestarted,
+ long runtimeStartElapsedTime, long runtimeStartUptime) {
mRuntimeRestarted = runtimeRestarted;
+ mRuntimeStartElapsedTime = runtimeStartElapsedTime;
+ mRuntimeStartUptime = runtimeStartUptime;
}
private void warnIfTooLong(long duration, SystemService service, String operation) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bf25928..c1c68e8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3364,7 +3364,8 @@
/**
* Update AMS states when an activity is resumed. This should only be called by
- * {@link ActivityStack#setResumedActivityLocked} when an activity is resumed.
+ * {@link ActivityStack#onActivityStateChanged(ActivityRecord, ActivityState, String)} when an
+ * activity is resumed.
*/
@GuardedBy("this")
void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
@@ -5149,35 +5150,39 @@
public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
IRecentsAnimationRunner recentsAnimationRunner) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
+ final int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
try {
+ final int recentsUid;
+ final String recentsPackage;
+ final List<IBinder> topVisibleActivities;
synchronized (this) {
- final int recentsUid = mRecentTasks.getRecentsComponentUid();
final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
- final String recentsPackage = recentsComponent.getPackageName();
-
- // If provided, kick off the request for the assist data in the background before
- // starting the activity
- if (assistDataReceiver != null) {
- final AppOpsManager appOpsManager = (AppOpsManager)
- mContext.getSystemService(Context.APP_OPS_SERVICE);
- final AssistDataReceiverProxy proxy = new AssistDataReceiverProxy(
- assistDataReceiver, recentsPackage);
- final AssistDataRequester requester = new AssistDataRequester(mContext, this,
- mWindowManager, appOpsManager, proxy, this,
- OP_ASSIST_STRUCTURE, OP_NONE);
- requester.requestAssistData(mStackSupervisor.getTopVisibleActivities(),
- true /* fetchData */, false /* fetchScreenshots */,
- true /* allowFetchData */, false /* alloweFetchScreenshots */,
- recentsUid, recentsPackage);
- }
+ recentsPackage = recentsComponent.getPackageName();
+ recentsUid = mRecentTasks.getRecentsComponentUid();
+ topVisibleActivities = mStackSupervisor.getTopVisibleActivities();
// Start a new recents animation
final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
- mActivityStartController, mWindowManager, mUserController);
+ mActivityStartController, mWindowManager, mUserController, callingPid);
anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
recentsUid);
}
+
+ // If provided, kick off the request for the assist data in the background. Do not hold
+ // the AM lock as this will just proxy directly to the assist data receiver provided.
+ if (assistDataReceiver != null) {
+ final AppOpsManager appOpsManager = (AppOpsManager)
+ mContext.getSystemService(Context.APP_OPS_SERVICE);
+ final AssistDataReceiverProxy proxy = new AssistDataReceiverProxy(
+ assistDataReceiver, recentsPackage);
+ final AssistDataRequester requester = new AssistDataRequester(mContext, this,
+ mWindowManager, appOpsManager, proxy, this, OP_ASSIST_STRUCTURE, OP_NONE);
+ requester.requestAssistData(topVisibleActivities,
+ true /* fetchData */, false /* fetchScreenshots */,
+ true /* allowFetchData */, false /* allowFetchScreenshots */,
+ recentsUid, recentsPackage);
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -14337,6 +14342,28 @@
}
}
+ void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
+ synchronized (ActivityManagerService.this) {
+ final ProcessRecord pr;
+ synchronized (mPidsSelfLocked) {
+ pr = mPidsSelfLocked.get(pid);
+ if (pr == null) {
+ Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid);
+ return;
+ }
+ }
+ if (pr.runningRemoteAnimation == runningRemoteAnimation) {
+ return;
+ }
+ pr.runningRemoteAnimation = runningRemoteAnimation;
+ if (DEBUG_OOM_ADJ) {
+ Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation
+ + " for pid=" + pid);
+ }
+ updateOomAdjLocked(pr, true);
+ }
+ }
+
public final void enterSafeMode() {
synchronized(this) {
// It only makes sense to do this before the system is ready
@@ -22747,6 +22774,12 @@
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making top: " + app);
+ } else if (app.runningRemoteAnimation) {
+ adj = ProcessList.VISIBLE_APP_ADJ;
+ schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ app.adjType = "running-remote-anim";
+ procState = PROCESS_STATE_CUR_TOP;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making running remote anim: " + app);
} else if (app.instr != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -22822,7 +22855,9 @@
app.adjType = "vis-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app);
}
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ }
app.cached = false;
app.empty = false;
foregroundActivities = true;
@@ -22845,7 +22880,9 @@
app.adjType = "pause-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app);
}
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ }
app.cached = false;
app.empty = false;
foregroundActivities = true;
@@ -25986,6 +26023,11 @@
}
}
+ @Override
+ public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
+ ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation);
+ }
+
/**
* Called after the network policy rules are updated by
* {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid}
@@ -26535,6 +26577,7 @@
throws RemoteException {
enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
"registerRemoteAnimations");
+ definition.setCallingPid(Binder.getCallingPid());
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r == null) {
@@ -26554,6 +26597,7 @@
RemoteAnimationAdapter adapter) throws RemoteException {
enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
"registerRemoteAnimationForNextActivityStart");
+ adapter.setCallingPid(Binder.getCallingPid());
synchronized (this) {
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e6d6fdf..59f027a 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1636,7 +1636,11 @@
mRecentTransitions.add(new StateTransition(prev, state, reason));
- mState = state;
+ final TaskRecord parent = getTask();
+
+ if (parent != null) {
+ parent.onActivityStateChanged(this, state, reason);
+ }
if (isState(DESTROYING, DESTROYED)) {
makeFinishingLocked();
@@ -2111,7 +2115,7 @@
if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this) || stopped) {
final ActivityStack stack = mStackSupervisor.getFocusedStack();
// Try to use the one which is closest to top.
- ActivityRecord r = stack.mResumedActivity;
+ ActivityRecord r = stack.getResumedActivity();
if (r == null) {
r = stack.mPausingActivity;
}
@@ -2208,7 +2212,7 @@
return false;
}
final ActivityStack stack = getStack();
- if (stack == null || this == stack.mResumedActivity || this == stack.mPausingActivity
+ if (stack == null || this == stack.getResumedActivity() || this == stack.mPausingActivity
|| !haveState || !stopped) {
// We're not ready for this kind of thing.
return false;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f4a4af2..2d7520e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -347,6 +347,9 @@
private final Rect mTmpRect2 = new Rect();
private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic();
+ /** List for processing through a set of activities */
+ private final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>();
+
/** Run all ActivityStacks through this */
protected final ActivityStackSupervisor mStackSupervisor;
@@ -472,6 +475,28 @@
return mWindowContainerController;
}
+ /**
+ * This should be called when an activity in a child task changes state. This should only
+ * be called from
+ * {@link TaskRecord#onActivityStateChanged(ActivityRecord, ActivityState, String)}.
+ * @param record The {@link ActivityRecord} whose state has changed.
+ * @param state The new state.
+ * @param reason The reason for the change.
+ */
+ void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
+ if (record == mResumedActivity && state != RESUMED) {
+ clearResumedActivity(reason + " - onActivityStateChanged");
+ }
+
+ if (state == RESUMED) {
+ if (DEBUG_STACK) Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:"
+ + reason);
+ mResumedActivity = record;
+ mService.setResumedActivityUncheckLocked(record, reason);
+ mStackSupervisor.mRecentTasks.add(record.getTask());
+ }
+ }
+
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWindowingMode = getWindowingMode();
@@ -1226,7 +1251,7 @@
void minimalResumeActivityLocked(ActivityRecord r) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
+ " callers=" + Debug.getCallers(5));
- setResumedActivityLocked(r, "minimalResumeActivityLocked");
+ r.setState(RESUMED, "minimalResumeActivityLocked");
r.completeResumeLocked();
setLaunchTime(r);
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
@@ -1451,7 +1476,6 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
- mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
@@ -2260,32 +2284,40 @@
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
+
+ // When resuming the top activity, it may be necessary to pause the top activity (for
+ // example, returning to the lock screen. We suppress the normal pause logic in
+ // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
+ // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
+ // to ensure any necessary pause logic occurs. In the case where the Activity will be
+ // shown regardless of the lock screen, the call to
+ // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
+ final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
+ if (next == null || !next.canTurnScreenOn()) {
+ checkReadyForSleep();
+ }
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
- // When resuming the top activity, it may be necessary to pause the top activity (for
- // example, returning to the lock screen. We suppress the normal pause logic in
- // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
- // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
- // any necessary pause logic occurs. In the case where the Activity will be shown regardless
- // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
- // is skipped.
- final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
- if (next == null || !next.canTurnScreenOn()) {
- checkReadyForSleep();
- }
-
return result;
}
- void setResumedActivityLocked(ActivityRecord r, String reason) {
- // TODO: move mResumedActivity to stack supervisor,
- // there should only be 1 global copy of resumed activity.
- mResumedActivity = r;
- r.setState(RESUMED, "setResumedActivityLocked");
- mService.setResumedActivityUncheckLocked(r, reason);
- mStackSupervisor.mRecentTasks.add(r.getTask());
+ /**
+ * Returns the currently resumed activity.
+ */
+ protected ActivityRecord getResumedActivity() {
+ return mResumedActivity;
+ }
+
+ /**
+ * Clears reference to currently resumed activity.
+ */
+ private void clearResumedActivity(String reason) {
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "clearResumedActivity: " + mResumedActivity + " reason:"
+ + reason);
+
+ mResumedActivity = null;
}
@GuardedBy("mService")
@@ -2574,7 +2606,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
+ " (in existing)");
- setResumedActivityLocked(next, "resumeTopActivityInnerLocked");
+ next.setState(RESUMED, "resumeTopActivityInnerLocked");
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
@@ -2676,7 +2708,7 @@
+ lastState + ": " + next);
next.setState(lastState, "resumeTopActivityInnerLocked");
if (lastStack != null) {
- lastStack.mResumedActivity = lastResumedActivity;
+ lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
}
Slog.i(TAG, "Restarting because process died: " + next);
if (!next.hasBeenLaunched) {
@@ -2822,7 +2854,7 @@
true /* includingParents */);
}
- final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
+ void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTask();
final int taskId = rTask.taskId;
@@ -3390,8 +3422,8 @@
* @param allowFocusSelf Is the focus allowed to remain on the same stack.
*/
private boolean adjustFocusToNextFocusableStack(String reason, boolean allowFocusSelf) {
- final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(
- allowFocusSelf ? null : this);
+ final ActivityStack stack =
+ mStackSupervisor.getNextFocusableStackLocked(this, !allowFocusSelf);
final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {
return false;
@@ -3776,9 +3808,6 @@
mStackSupervisor.mStoppingActivities.remove(r);
mStackSupervisor.mGoingToSleepActivities.remove(r);
mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(r);
- if (mResumedActivity == r) {
- mResumedActivity = null;
- }
final ActivityState prevState = r.getState();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
@@ -3991,7 +4020,7 @@
*/
void onActivityRemovedFromStack(ActivityRecord r) {
if (mResumedActivity == r) {
- mResumedActivity = null;
+ clearResumedActivity("onActivityRemovedFromStack");
}
if (mPausingActivity == r) {
mPausingActivity = null;
@@ -4405,11 +4434,15 @@
"Removing app " + app + " from history with " + i + " entries");
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- --i;
+ mTmpActivities.clear();
+ mTmpActivities.addAll(activities);
+
+ while (!mTmpActivities.isEmpty()) {
+ final int targetIndex = mTmpActivities.size() - 1;
+ final ActivityRecord r = mTmpActivities.remove(targetIndex);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
- "Record #" + i + " " + r + ": app=" + r.app);
+ "Record #" + targetIndex + " " + r + ": app=" + r.app);
+
if (r.app == app) {
if (r.visible) {
hasVisibleActivities = true;
@@ -4827,9 +4860,11 @@
ComponentName homeActivity = null;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- int numActivities = activities.size();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- ActivityRecord r = activities.get(activityNdx);
+ mTmpActivities.clear();
+ mTmpActivities.addAll(activities);
+
+ while (!mTmpActivities.isEmpty()) {
+ ActivityRecord r = mTmpActivities.remove(0);
final boolean sameComponent =
(r.packageName.equals(packageName) && (filterByClasses == null
|| filterByClasses.contains(r.realActivity.getClassName())))
@@ -4862,12 +4897,8 @@
r.app = null;
}
lastTask = r.getTask();
- if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
- true)) {
- // r has been deleted from mActivities, accommodate.
- --numActivities;
- --activityNdx;
- }
+ finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
+ true);
}
}
}
@@ -5181,7 +5212,7 @@
+ " other stack to this stack mResumedActivity=" + mResumedActivity
+ " other mResumedActivity=" + topRunningActivity);
}
- mResumedActivity = topRunningActivity;
+ topRunningActivity.setState(RESUMED, "positionChildAt");
}
// The task might have already been running and its visibility needs to be synchronized with
@@ -5226,7 +5257,7 @@
// so that we don't resume the same activity again in the new stack.
// Apps may depend on onResume()/onPause() being called in pairs.
if (setResume) {
- mResumedActivity = r;
+ r.setState(RESUMED, "moveToFrontAndResumeStateIfNeeded");
updateLRUListLocked(r);
}
// If the activity was previously pausing, then ensure we transfer that as well
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d372bd8..869c635 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -679,7 +679,7 @@
void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
if (!focusCandidate.isFocusable()) {
// The focus candidate isn't focusable. Move focus to the top stack that is focusable.
- focusCandidate = getNextFocusableStackLocked(focusCandidate);
+ focusCandidate = getNextFocusableStackLocked(focusCandidate, false /* ignoreCurrent */);
}
if (focusCandidate != mFocusedStack) {
@@ -930,7 +930,7 @@
if (stack == null) {
return null;
}
- ActivityRecord resumedActivity = stack.mResumedActivity;
+ ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity == null || resumedActivity.app == null) {
resumedActivity = stack.mPausingActivity;
if (resumedActivity == null || resumedActivity.app == null) {
@@ -985,7 +985,7 @@
if (!isFocusedStack(stack) || stack.numActivities() == 0) {
continue;
}
- final ActivityRecord resumedActivity = stack.mResumedActivity;
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity == null || !resumedActivity.idle) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
+ stack.mStackId + " " + resumedActivity + " not idle");
@@ -1004,7 +1004,7 @@
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
if (isFocusedStack(stack)) {
- final ActivityRecord r = stack.mResumedActivity;
+ final ActivityRecord r = stack.getResumedActivity();
if (r != null && !r.isState(RESUMED)) {
return false;
}
@@ -1025,7 +1025,7 @@
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
- final ActivityRecord r = stack.mResumedActivity;
+ final ActivityRecord r = stack.getResumedActivity();
if (r != null) {
if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) {
return false;
@@ -1051,9 +1051,9 @@
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
- if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
+ if (!isFocusedStack(stack) && stack.getResumedActivity() != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
- " mResumedActivity=" + stack.mResumedActivity);
+ " mResumedActivity=" + stack.getResumedActivity());
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
@@ -2063,8 +2063,9 @@
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
if (isFocusedStack(stack)) {
- if (stack.mResumedActivity != null) {
- fgApp = stack.mResumedActivity.app;
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity != null) {
+ fgApp = resumedActivity.app;
} else if (stack.mPausingActivity != null) {
fgApp = stack.mPausingActivity.app;
}
@@ -2428,27 +2429,50 @@
* Get next focusable stack in the system. This will search across displays and stacks
* in last-focused order for a focusable and visible stack, different from the target stack.
*
- * @param currentFocus The stack that previously had focus and thus needs to be ignored when
- * searching for next candidate.
+ * @param currentFocus The stack that previously had focus.
+ * @param ignoreCurrent If we should ignore {@param currentFocus} when searching for next
+ * candidate.
* @return Next focusable {@link ActivityStack}, null if not found.
*/
- ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+ ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus, boolean ignoreCurrent) {
mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
+ final int currentWindowingMode = currentFocus != null
+ ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+ ActivityStack candidate = null;
for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
final int displayId = mTmpOrderedDisplayIds.get(i);
// If a display is registered in WM, it must also be available in AM.
final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
for (int j = display.getChildCount() - 1; j >= 0; --j) {
final ActivityStack stack = display.getChildAt(j);
- if (stack != currentFocus && stack.isFocusable()
- && stack.shouldBeVisible(null)) {
- return stack;
+ if (ignoreCurrent && stack == currentFocus) {
+ continue;
}
+ if (!stack.isFocusable() || !stack.shouldBeVisible(null)) {
+ continue;
+ }
+
+ if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
+ // If the currently focused stack is in split-screen secondary we would prefer
+ // the focus to move to another split-screen secondary stack or fullscreen stack
+ // over the primary split screen stack to avoid:
+ // - Moving the focus to the primary split-screen stack when it can't be focused
+ // because it will be minimized, but AM doesn't know that yet
+ // - primary split-screen stack overlapping with a fullscreen stack when a
+ // fullscreen stack is higher in z than the next split-screen stack. Assistant
+ // stack, I am looking at you...
+ // We only move the focus to the primary-split screen stack if there isn't a
+ // better alternative.
+ candidate = stack;
+ continue;
+ }
+ return stack;
}
}
- return null;
+ return candidate;
}
/**
@@ -3734,7 +3758,7 @@
+ " state=" + state);
}
} else {
- final ActivityRecord resumed = stack.mResumedActivity;
+ final ActivityRecord resumed = stack.getResumedActivity();
if (resumed != null && resumed == r) Slog.e(TAG,
"validateTop...: back stack has resumed activity r=" + r
+ " state=" + state);
@@ -3884,7 +3908,7 @@
printed = true;
needSep = false;
}
- pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep,
+ pr = printThisActivity(pw, stack.getResumedActivity(), dumpPackage, needSep,
" mResumedActivity: ");
if (pr) {
printed = true;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index fcdf3d2..bd53eac 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -820,8 +820,8 @@
// If we are starting an activity that is not from the same uid as the currently resumed
// one, check whether app switches are allowed.
- if (voiceSession == null && (stack.mResumedActivity == null
- || stack.mResumedActivity.info.applicationInfo.uid != realCallingUid)) {
+ if (voiceSession == null && (stack.getResumedActivity() == null
+ || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1f60755..0bf2691 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -129,6 +129,12 @@
// When true the process will oom adj score will be set to
// ProcessList#PERCEPTIBLE_APP_ADJ at minimum to reduce the chance
// of the process getting killed.
+ boolean runningRemoteAnimation; // Is the process currently running a RemoteAnimation? When true
+ // the process will be set to use the
+ // ProcessList#SCHED_GROUP_TOP_APP scheduling group to boost
+ // performance, as well as oom adj score will be set to
+ // ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance
+ // of the process getting killed.
boolean pendingUiClean; // Want to clean up resources from showing UI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY
@@ -336,9 +342,10 @@
pw.print(" hasAboveClient="); pw.print(hasAboveClient);
pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
}
- if (hasTopUi || hasOverlayUi) {
+ if (hasTopUi || hasOverlayUi || runningRemoteAnimation) {
pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi);
- pw.print(" hasOverlayUi="); pw.println(hasOverlayUi);
+ pw.print(" hasOverlayUi="); pw.print(hasOverlayUi);
+ pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation);
}
if (foregroundServices || forcingToImportant != null) {
pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 99f5298..f1b3dfa 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -828,6 +828,25 @@
}
/**
+ * @return ids of tasks that are presented in Recents UI.
+ */
+ SparseBooleanArray getRecentTaskIds() {
+ final SparseBooleanArray res = new SparseBooleanArray();
+ final int size = mTasks.size();
+ int numVisibleTasks = 0;
+ for (int i = 0; i < size; i++) {
+ final TaskRecord tr = mTasks.get(i);
+ if (isVisibleRecentTask(tr)) {
+ numVisibleTasks++;
+ if (isInVisibleRange(tr, numVisibleTasks)) {
+ res.put(tr.taskId, true);
+ }
+ }
+ }
+ return res;
+ }
+
+ /**
* @return the task in the task list with the given {@param id} if one exists.
*/
TaskRecord getTask(int id) {
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 4b1594c..9121568 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -16,7 +16,6 @@
package com.android.server.am;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
@@ -50,6 +49,7 @@
private final WindowManagerService mWindowManager;
private final UserController mUserController;
private final Handler mHandler;
+ private final int mCallingPid;
private final Runnable mCancelAnimationRunnable;
@@ -58,13 +58,14 @@
RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
ActivityStartController activityStartController, WindowManagerService wm,
- UserController userController) {
+ UserController userController, int callingPid) {
mService = am;
mStackSupervisor = stackSupervisor;
mActivityStartController = activityStartController;
mHandler = new Handler(mStackSupervisor.mLooper);
mWindowManager = wm;
mUserController = userController;
+ mCallingPid = callingPid;
mCancelAnimationRunnable = () -> {
// The caller has not finished the animation in a predefined amount of time, so
@@ -94,9 +95,10 @@
}
}
+ mService.setRunningRemoteAnimation(mCallingPid, true);
+
mWindowManager.deferSurfaceLayout();
try {
-
final ActivityDisplay display;
if (hasExistingHomeActivity) {
// Move the home activity into place for the animation if it is not already top most
@@ -136,7 +138,7 @@
// started
mWindowManager.cancelRecentsAnimation();
mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
- display.mDisplayId);
+ display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds());
// If we updated the launch-behind state, update the visibility of the activities after
// we fetch the visible tasks to be controlled by the animation
@@ -153,6 +155,8 @@
synchronized (mService) {
if (mWindowManager.getRecentsAnimationController() == null) return;
+ mService.setRunningRemoteAnimation(mCallingPid, false);
+
mWindowManager.inSurfaceTransaction(() -> {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
"RecentsAnimation#onAnimationFinished_inSurfaceTransaction");
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index d08111e..ac6f01f 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -121,10 +121,16 @@
if (mOriginalOptions != null) {
checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
mOriginalCallingPid, mOriginalCallingUid);
+ if (mOriginalOptions.getRemoteAnimationAdapter() != null) {
+ mOriginalOptions.getRemoteAnimationAdapter().setCallingPid(mOriginalCallingPid);
+ }
}
if (mCallerOptions != null) {
checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions,
mRealCallingPid, mRealCallingUid);
+ if (mCallerOptions.getRemoteAnimationAdapter() != null) {
+ mCallerOptions.getRemoteAnimationAdapter().setCallingPid(mRealCallingPid);
+ }
}
return mergeActivityOptions(mOriginalOptions, mCallerOptions);
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 6f6e0d9..7280f57 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -650,7 +650,7 @@
final ActivityRecord r = topRunningActivityLocked();
final boolean wasFocused = r != null && supervisor.isFocusedStack(sourceStack)
&& (topRunningActivityLocked() == r);
- final boolean wasResumed = r != null && sourceStack.mResumedActivity == r;
+ final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
// In some cases the focused stack isn't the front stack. E.g. pinned stack.
@@ -1754,6 +1754,22 @@
return !mTmpConfig.equals(newConfig);
}
+ /**
+ * This should be called when an child activity changes state. This should only
+ * be called from
+ * {@link ActivityRecord#setState(ActivityState, String)} .
+ * @param record The {@link ActivityRecord} whose state has changed.
+ * @param state The new state.
+ * @param reason The reason for the change.
+ */
+ void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
+ final ActivityStack parent = getStack();
+
+ if (parent != null) {
+ parent.onActivityStateChanged(record, state, reason);
+ }
+ }
+
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final boolean wasInMultiWindowMode = inMultiWindowMode();
@@ -2002,7 +2018,7 @@
} else if (intent != null) {
sb.append(" I=");
sb.append(intent.getComponent().flattenToShortString());
- } else if (affinityIntent != null) {
+ } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
sb.append(" aI=");
sb.append(affinityIntent.getComponent().flattenToShortString());
} else {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3b5cad6..f577d09 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -39,6 +39,7 @@
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -144,6 +145,7 @@
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -255,6 +257,7 @@
private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
+ private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
// end of messages handled under wakelock
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -264,6 +267,8 @@
// retry delay in case of failure to indicate system ready to AudioFlinger
private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
+ private static final int BT_HEARING_AID_GAIN_MIN = -128;
+
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -572,7 +577,7 @@
AudioSystem.DEVICE_OUT_HDMI_ARC |
AudioSystem.DEVICE_OUT_SPDIF |
AudioSystem.DEVICE_OUT_AUX_LINE;
- int mFullVolumeDevices = 0;
+ int mFullVolumeDevices = AudioSystem.DEVICE_OUT_HEARING_AID;
private final boolean mMonitorRotation;
@@ -589,6 +594,10 @@
private final MediaFocusControl mMediaFocusControl;
+ // Reference to BluetoothA2dp to query for volume.
+ private BluetoothHearingAid mHearingAid;
+ // lock always taken synchronized on mConnectedDevices
+ private final Object mHearingAidLock = new Object();
// Reference to BluetoothA2dp to query for AbsoluteVolume.
private BluetoothA2dp mA2dp;
// lock always taken synchronized on mConnectedDevices
@@ -848,6 +857,8 @@
if (adapter != null) {
adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.A2DP);
+ adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+ BluetoothProfile.HEARING_AID);
}
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
@@ -1606,6 +1617,20 @@
}
}
+ // Check if volume update should be send to Hearing Aid
+ if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ synchronized (mHearingAidLock) {
+ if (mHearingAid != null) {
+ //hearing aid expect volume value in range -128dB to 0dB
+ int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, newIndex/10,
+ AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (gainDB < BT_HEARING_AID_GAIN_MIN)
+ gainDB = BT_HEARING_AID_GAIN_MIN;
+ mHearingAid.setVolume(gainDB);
+ }
+ }
+ }
+
// Check if volume update should be sent to Hdmi system audio.
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
@@ -1851,6 +1876,19 @@
}
}
+ if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ synchronized (mHearingAidLock) {
+ if (mHearingAid != null) {
+ //hearing aid expect volume value in range -128dB to 0dB
+ int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, index/10, AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (gainDB < BT_HEARING_AID_GAIN_MIN)
+ gainDB = BT_HEARING_AID_GAIN_MIN;
+ mHearingAid.setVolume(gainDB);
+
+ }
+ }
+ }
+
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
}
@@ -1914,7 +1952,16 @@
}
mUserSelectedVolumeControlStream = false;
} else {
- mForceControlStreamClient = new ForceControlStreamClient(cb);
+ if (null == mForceControlStreamClient) {
+ mForceControlStreamClient = new ForceControlStreamClient(cb);
+ } else {
+ if (mForceControlStreamClient.getBinder() == cb) {
+ Log.d(TAG, "forceVolumeControlStream cb:" + cb + " is already linked.");
+ } else {
+ mForceControlStreamClient.release();
+ mForceControlStreamClient = new ForceControlStreamClient(cb);
+ }
+ }
}
}
}
@@ -1954,6 +2001,10 @@
mCb = null;
}
}
+
+ public IBinder getBinder() {
+ return mCb;
+ }
}
private void sendBroadcastToAll(Intent intent) {
@@ -3595,6 +3646,30 @@
}
break;
+ case BluetoothProfile.HEARING_AID:
+ synchronized (mConnectedDevices) {
+ synchronized (mHearingAidLock) {
+ mHearingAid = (BluetoothHearingAid) proxy;
+ deviceList = mHearingAid.getConnectedDevices();
+ if (deviceList.size() > 0) {
+ btDevice = deviceList.get(0);
+ int state = mHearingAid.getConnectionState(btDevice);
+ int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
+ int delay = checkSendBecomingNoisyIntent(
+ AudioSystem.DEVICE_OUT_HEARING_AID, intState,
+ AudioSystem.DEVICE_NONE);
+ queueMsgUnderWakeLock(mAudioHandler,
+ MSG_SET_HEARING_AID_CONNECTION_STATE,
+ state,
+ 0 /* arg2 unused */,
+ btDevice,
+ delay);
+ }
+ }
+ }
+
+ break;
+
default:
break;
}
@@ -3614,6 +3689,10 @@
disconnectHeadset();
break;
+ case BluetoothProfile.HEARING_AID:
+ disconnectHearingAid();
+ break;
+
default:
break;
}
@@ -3624,6 +3703,7 @@
disconnectA2dp();
disconnectA2dpSink();
disconnectHeadset();
+ disconnectHearingAid();
}
void disconnectA2dp() {
@@ -3675,6 +3755,29 @@
}
}
+ void disconnectHearingAid() {
+ synchronized (mConnectedDevices) {
+ synchronized (mHearingAidLock) {
+ ArraySet<String> toRemove = null;
+ // Disconnect ALL DEVICE_OUT_HEARING_AID devices
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+ if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ toRemove = toRemove != null ? toRemove : new ArraySet<String>();
+ toRemove.add(deviceSpec.mDeviceAddress);
+ }
+ }
+ if (toRemove != null) {
+ int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
+ 0, AudioSystem.DEVICE_NONE);
+ for (int i = 0; i < toRemove.size(); i++) {
+ makeHearingAidDeviceUnavailable(toRemove.valueAt(i) /*, delay*/);
+ }
+ }
+ }
+ }
+ }
+
private void onCheckMusicActive(String caller) {
synchronized (mSafeMediaVolumeState) {
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
@@ -4186,7 +4289,8 @@
handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
- msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
+ msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
+ msg == MSG_SET_HEARING_AID_CONNECTION_STATE) {
mLastDeviceConnectMsgTime = time;
}
}
@@ -4289,6 +4393,33 @@
@Override
public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
{
+ Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState");
+
+ setBluetoothHearingAidDeviceConnectionState(
+ device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
+ }
+
+ public int setBluetoothHearingAidDeviceConnectionState(
+ BluetoothDevice device, int state, boolean suppressNoisyIntent,
+ int musicDevice)
+ {
+ int delay;
+ synchronized (mConnectedDevices) {
+ if (!suppressNoisyIntent) {
+ int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
+ delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
+ intState, musicDevice);
+ } else {
+ delay = 0;
+ }
+ queueMsgUnderWakeLock(mAudioHandler,
+ MSG_SET_HEARING_AID_CONNECTION_STATE,
+ state,
+ 0 /* arg2 unused */,
+ device,
+ delay);
+ }
+ return delay;
}
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
@@ -5230,6 +5361,11 @@
mAudioEventWakeLock.release();
break;
+ case MSG_SET_HEARING_AID_CONNECTION_STATE:
+ onSetHearingAidConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+ mAudioEventWakeLock.release();
+ break;
+
case MSG_A2DP_DEVICE_CONFIG_CHANGE:
onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
mAudioEventWakeLock.release();
@@ -5422,14 +5558,8 @@
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
- synchronized (mCurAudioRoutes) {
- // Remove A2DP routes as well
- if (mCurAudioRoutes.bluetoothName != null) {
- mCurAudioRoutes.bluetoothName = null;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
- }
- }
+ // Remove A2DP routes as well
+ setCurrentAudioRouteName(null);
}
// must be called synchronized on mConnectedDevices
@@ -5465,6 +5595,28 @@
}
// must be called synchronized on mConnectedDevices
+ private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
+ AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+ mConnectedDevices.put(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
+ new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name,
+ address));
+ sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
+ }
+
+ // must be called synchronized on mConnectedDevices
+ private void makeHearingAidDeviceUnavailable(String address) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+ mConnectedDevices.remove(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
+ // Remove Hearing Aid routes as well
+ setCurrentAudioRouteName(null);
+ }
+
+ // must be called synchronized on mConnectedDevices
private void cancelA2dpDeviceTimeout() {
mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
}
@@ -5505,13 +5657,7 @@
} else {
makeA2dpDeviceUnavailableNow(address);
}
- synchronized (mCurAudioRoutes) {
- if (mCurAudioRoutes.bluetoothName != null) {
- mCurAudioRoutes.bluetoothName = null;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
- }
- }
+ setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
@@ -5527,14 +5673,7 @@
}
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
- synchronized (mCurAudioRoutes) {
- String name = btDevice.getAliasName();
- if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
- mCurAudioRoutes.bluetoothName = name;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
- }
- }
+ setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
@@ -5565,6 +5704,46 @@
}
}
+ private void onSetHearingAidConnectionState(BluetoothDevice btDevice, int state)
+ {
+ if (DEBUG_DEVICES) {
+ Log.d(TAG, "onSetHearingAidConnectionState btDevice=" + btDevice+", state=" + state);
+ }
+ if (btDevice == null) {
+ return;
+ }
+ String address = btDevice.getAddress();
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ address = "";
+ }
+
+ synchronized (mConnectedDevices) {
+ final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID,
+ btDevice.getAddress());
+ final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+ boolean isConnected = deviceSpec != null;
+
+ if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+ makeHearingAidDeviceUnavailable(address);
+ setCurrentAudioRouteName(null);
+ } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+ makeHearingAidDeviceAvailable(address, btDevice.getName(),
+ "onSetHearingAidConnectionState");
+ setCurrentAudioRouteName(btDevice.getAliasName());
+ }
+ }
+ }
+
+ private void setCurrentAudioRouteName(String name){
+ synchronized (mCurAudioRoutes) {
+ if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
+ mCurAudioRoutes.bluetoothName = name;
+ sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ }
+ }
+ }
+
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
if (DEBUG_DEVICES) {
@@ -5683,7 +5862,9 @@
}
// ignore condition on device being actually used for music when in communication
// because music routing is altered in this case.
- if (((device == musicDevice) || isInCommunication()) && (device == devices)) {
+ // also checks whether media routing if affected by a dynamic policy
+ if (((device == musicDevice) || isInCommunication()) && (device == devices)
+ && !hasMediaDynamicPolicy()) {
mAudioHandler.removeMessages(MSG_BROADCAST_AUDIO_BECOMING_NOISY);
sendMsg(mAudioHandler,
MSG_BROADCAST_AUDIO_BECOMING_NOISY,
@@ -5698,6 +5879,7 @@
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
+ mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) ||
mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
synchronized (mLastDeviceConnectMsgTime) {
long time = SystemClock.uptimeMillis();
@@ -5709,6 +5891,24 @@
return delay;
}
+ /**
+ * @return true if there is currently a registered dynamic mixing policy that affects media
+ */
+ private boolean hasMediaDynamicPolicy() {
+ synchronized (mAudioPolicies) {
+ if (mAudioPolicies.isEmpty()) {
+ return false;
+ }
+ final Collection<AudioPolicyProxy> appColl = mAudioPolicies.values();
+ for (AudioPolicyProxy app : appColl) {
+ if (app.hasMixAffectingUsage(AudioAttributes.USAGE_MEDIA)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
private void updateAudioRoutes(int device, int state)
{
int connType = 0;
@@ -7407,6 +7607,15 @@
Binder.restoreCallingIdentity(identity);
}
+ boolean hasMixAffectingUsage(int usage) {
+ for (AudioMix mix : mMixes) {
+ if (mix.isAffectingUsage(usage)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void addMixes(@NonNull ArrayList<AudioMix> mixes) {
// TODO optimize to not have to unregister the mixes already in place
synchronized (mMixes) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index 2a9d386..ff1e29b 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -120,6 +120,12 @@
}
}
+ private boolean checkConfiguredLocked() {
+ if (mTunerCallback.isInitialConfigurationDone()) return true;
+ Slog.w(TAG, "Initial configuration is still pending, skipping the operation");
+ return false;
+ }
+
@Override
public void setConfiguration(RadioManager.BandConfig config) {
if (config == null) {
@@ -170,6 +176,7 @@
public void step(boolean directionDown, boolean skipSubChannel) {
synchronized (mLock) {
checkNotClosedLocked();
+ if (!checkConfiguredLocked()) return;
nativeStep(mNativeContext, directionDown, skipSubChannel);
}
}
@@ -178,6 +185,7 @@
public void scan(boolean directionDown, boolean skipSubChannel) {
synchronized (mLock) {
checkNotClosedLocked();
+ if (!checkConfiguredLocked()) return;
nativeScan(mNativeContext, directionDown, skipSubChannel);
}
}
@@ -190,6 +198,7 @@
Slog.i(TAG, "Tuning to " + selector);
synchronized (mLock) {
checkNotClosedLocked();
+ if (!checkConfiguredLocked()) return;
nativeTune(mNativeContext, selector);
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 7ad73c3..32b1d1a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -47,6 +47,7 @@
@NonNull private final ITunerCallback mClientCallback;
private final AtomicReference<ProgramList.Filter> mProgramListFilter = new AtomicReference<>();
+ private boolean mInitialConfigurationDone = false;
TunerCallback(@NonNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev) {
mTuner = tuner;
@@ -95,6 +96,10 @@
mProgramListFilter.set(null);
}
+ boolean isInitialConfigurationDone() {
+ return mInitialConfigurationDone;
+ }
+
@Override
public void onError(int status) {
dispatch(() -> mClientCallback.onError(status));
@@ -107,6 +112,7 @@
@Override
public void onConfigurationChanged(RadioManager.BandConfig config) {
+ mInitialConfigurationDone = true;
dispatch(() -> mClientCallback.onConfigurationChanged(config));
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 406231a..954c001 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -101,7 +101,9 @@
}
TunerSession session = module.openSession(callback);
- session.setConfiguration(legacyConfig);
+ if (legacyConfig != null) {
+ session.setConfiguration(legacyConfig);
+ }
return session;
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 5af19ec..6919282 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -23,6 +23,8 @@
import android.hardware.broadcastradio.V2_0.Announcement;
import android.hardware.broadcastradio.V2_0.DabTableEntry;
import android.hardware.broadcastradio.V2_0.IdentifierType;
+import android.hardware.broadcastradio.V2_0.Metadata;
+import android.hardware.broadcastradio.V2_0.MetadataKey;
import android.hardware.broadcastradio.V2_0.ProgramFilter;
import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
import android.hardware.broadcastradio.V2_0.ProgramInfo;
@@ -34,6 +36,7 @@
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.RadioMetadata;
import android.os.ParcelableException;
import android.util.Slog;
@@ -283,6 +286,77 @@
secondaryIds, null);
}
+ private enum MetadataType {
+ INT, STRING
+ }
+
+ private static class MetadataDef {
+ private MetadataType type;
+ private String key;
+ private MetadataDef(MetadataType type, String key) {
+ this.type = type;
+ this.key = key;
+ }
+ }
+
+ private static final Map<Integer, MetadataDef> metadataKeys;
+ static {
+ metadataKeys = new HashMap<>();
+ metadataKeys.put(MetadataKey.RDS_PS, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_RDS_PS));
+ metadataKeys.put(MetadataKey.RDS_PTY, new MetadataDef(
+ MetadataType.INT, RadioMetadata.METADATA_KEY_RDS_PTY));
+ metadataKeys.put(MetadataKey.RBDS_PTY, new MetadataDef(
+ MetadataType.INT, RadioMetadata.METADATA_KEY_RBDS_PTY));
+ metadataKeys.put(MetadataKey.RDS_RT, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_RDS_RT));
+ metadataKeys.put(MetadataKey.SONG_TITLE, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_TITLE));
+ metadataKeys.put(MetadataKey.SONG_ARTIST, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_ARTIST));
+ metadataKeys.put(MetadataKey.SONG_ALBUM, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_ALBUM));
+ metadataKeys.put(MetadataKey.STATION_ICON, new MetadataDef(
+ MetadataType.INT, RadioMetadata.METADATA_KEY_ICON));
+ metadataKeys.put(MetadataKey.ALBUM_ART, new MetadataDef(
+ MetadataType.INT, RadioMetadata.METADATA_KEY_ART));
+ metadataKeys.put(MetadataKey.PROGRAM_NAME, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_PROGRAM_NAME));
+ metadataKeys.put(MetadataKey.DAB_ENSEMBLE_NAME, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_DAB_ENSEMBLE_NAME));
+ metadataKeys.put(MetadataKey.DAB_ENSEMBLE_NAME_SHORT, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT));
+ metadataKeys.put(MetadataKey.DAB_SERVICE_NAME, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_DAB_SERVICE_NAME));
+ metadataKeys.put(MetadataKey.DAB_SERVICE_NAME_SHORT, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_DAB_SERVICE_NAME_SHORT));
+ metadataKeys.put(MetadataKey.DAB_COMPONENT_NAME, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_DAB_COMPONENT_NAME));
+ metadataKeys.put(MetadataKey.DAB_COMPONENT_NAME_SHORT, new MetadataDef(
+ MetadataType.STRING, RadioMetadata.METADATA_KEY_DAB_COMPONENT_NAME_SHORT));
+ }
+
+ private static @NonNull RadioMetadata metadataFromHal(@NonNull ArrayList<Metadata> meta) {
+ RadioMetadata.Builder builder = new RadioMetadata.Builder();
+
+ for (Metadata entry : meta) {
+ MetadataDef keyDef = metadataKeys.get(entry.key);
+ if (keyDef == null) {
+ Slog.i(TAG, "Ignored unknown metadata entry: " + MetadataKey.toString(entry.key));
+ continue;
+ }
+ if (keyDef.type == MetadataType.STRING) {
+ builder.putString(keyDef.key, entry.stringValue);
+ } else { // MetadataType.INT
+ /* Current java API use 32-bit values for int metadata,
+ * but we might change it in the future */
+ builder.putInt(keyDef.key, (int)entry.intValue);
+ }
+ }
+
+ return builder.build();
+ }
+
static @NonNull RadioManager.ProgramInfo programInfoFromHal(@NonNull ProgramInfo info) {
Collection<ProgramSelector.Identifier> relatedContent = info.relatedContent.stream().
map(id -> Objects.requireNonNull(programIdentifierFromHal(id))).
@@ -295,7 +369,7 @@
relatedContent,
info.infoFlags,
info.signalQuality,
- null, // TODO(b/69860743): metadata
+ metadataFromHal(info.metadata),
vendorInfoFromHal(info.vendorInfo)
);
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index daec97a..816ba0b 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -55,7 +55,7 @@
public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
try {
- IBroadcastRadio service = IBroadcastRadio.getService();
+ IBroadcastRadio service = IBroadcastRadio.getService(fqName);
if (service == null) return null;
Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 8efaa2a..8f3f099 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -90,7 +90,8 @@
if (ret == AudioSystem.AUDIO_STATUS_OK) {
mIsAudioConnected = connected;
} else {
- Slog.e(TAG, "Failed to notify AudioService about new state: " + connected);
+ Slog.e(TAG, "Failed to notify AudioService about new state: "
+ + connected + ", response was: " + ret);
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index df60c66..171f40e 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -69,6 +69,7 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
@@ -333,8 +334,16 @@
try {
final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
- builder.setUserId(focusedStack.userId);
- builder.setPackageName(focusedStack.topActivity.getPackageName());
+ if (focusedStack != null && focusedStack.topActivity != null) {
+ builder.setUserId(focusedStack.userId);
+ builder.setPackageName(focusedStack.topActivity.getPackageName());
+ } else {
+ // Ignore the event because we can't determine user / package.
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring event due to null focusedStack.");
+ }
+ return;
+ }
} catch (RemoteException e) {
// Really shouldn't be possible.
return;
@@ -649,7 +658,10 @@
}
public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId) {
- return new ParceledListSlice<>(mAmbientBrightnessStatsTracker.getUserStats(userId));
+ ArrayList<AmbientBrightnessDayStats> stats = mAmbientBrightnessStatsTracker.getUserStats(
+ userId);
+ return (stats != null) ? new ParceledListSlice<>(stats) : new ParceledListSlice<>(
+ Collections.EMPTY_LIST);
}
// Not allowed to keep the SensorEvent so used to copy the data we care about.
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a951d47..451acf4 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,12 +17,10 @@
package com.android.server.input;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.LocaleList;
import android.os.ShellCallback;
import android.util.Log;
import android.view.Display;
-import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
@@ -79,8 +77,6 @@
import android.os.MessageQueue;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ShellCommand;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -99,8 +95,7 @@
import android.view.PointerIcon;
import android.view.Surface;
import android.view.ViewConfiguration;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
+import android.widget.Toast;
import java.io.File;
import java.io.FileDescriptor;
@@ -137,7 +132,6 @@
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
- private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
// Pointer to native input manager service object.
private final long mPtr;
@@ -174,7 +168,8 @@
private final ArrayList<InputDevice>
mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
private boolean mKeyboardLayoutNotificationShown;
- private InputMethodSubtypeHandle mCurrentImeHandle;
+ private PendingIntent mKeyboardLayoutIntent;
+ private Toast mSwitchedKeyboardLayoutToast;
// State for vibrator tokens.
private Object mVibratorLock = new Object();
@@ -1368,82 +1363,6 @@
}
@Override // Binder call
- @Nullable
- public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
- String key = getLayoutDescriptor(identifier);
- final String keyboardLayoutDescriptor;
- synchronized (mDataStore) {
- keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
- }
-
- if (keyboardLayoutDescriptor == null) {
- return null;
- }
-
- final KeyboardLayout[] result = new KeyboardLayout[1];
- visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
- @Override
- public void visitKeyboardLayout(Resources resources,
- int keyboardLayoutResId, KeyboardLayout layout) {
- result[0] = layout;
- }
- });
- if (result[0] == null) {
- Slog.w(TAG, "Could not get keyboard layout with descriptor '"
- + keyboardLayoutDescriptor + "'.");
- }
- return result[0];
- }
-
- @Override
- public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
- String keyboardLayoutDescriptor) {
- if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
- "setKeyboardLayoutForInputDevice()")) {
- throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
- }
- if (keyboardLayoutDescriptor == null) {
- throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
- }
- if (imeInfo == null) {
- throw new IllegalArgumentException("imeInfo must not be null");
- }
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
- setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
- }
-
- private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
- InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
- String key = getLayoutDescriptor(identifier);
- synchronized (mDataStore) {
- try {
- if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
- if (DEBUG) {
- Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
- " for subtype " + imeHandle + " and device " + identifier +
- " using key " + key);
- }
- if (imeHandle.equals(mCurrentImeHandle)) {
- if (DEBUG) {
- Slog.d(TAG, "Layout for current subtype changed, switching layout");
- }
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = identifier;
- args.arg2 = imeHandle;
- mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
- }
- mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
- }
- }
-
- @Override // Binder call
public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
@@ -1462,7 +1381,8 @@
oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
}
if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
- && !Objects.equals(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
+ && !Objects.equals(oldLayout,
+ mDataStore.getCurrentKeyboardLayout(key))) {
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
}
} finally {
@@ -1505,51 +1425,43 @@
}
}
- // Must be called on handler.
- private void handleSwitchInputMethodSubtype(int userId,
- @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
- if (DEBUG) {
- Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
- + " ime=" + inputMethodInfo + " subtype=" + subtype);
- }
- if (inputMethodInfo == null) {
- Slog.d(TAG, "No InputMethod is running, ignoring change");
- return;
- }
- if (subtype != null && !"keyboard".equals(subtype.getMode())) {
- Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
- return;
- }
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
- if (!handle.equals(mCurrentImeHandle)) {
- mCurrentImeHandle = handle;
- handleSwitchKeyboardLayout(null, handle);
- }
+ public void switchKeyboardLayout(int deviceId, int direction) {
+ mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
}
// Must be called on handler.
- private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
- InputMethodSubtypeHandle handle) {
- synchronized (mInputDevicesLock) {
- for (InputDevice device : mInputDevices) {
- if (identifier != null && !device.getIdentifier().equals(identifier) ||
- !device.isFullKeyboard()) {
- continue;
+ private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+ final InputDevice device = getInputDevice(deviceId);
+ if (device != null) {
+ final boolean changed;
+ final String keyboardLayoutDescriptor;
+
+ String key = getLayoutDescriptor(device.getIdentifier());
+ synchronized (mDataStore) {
+ try {
+ changed = mDataStore.switchKeyboardLayout(key, direction);
+ keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
+ key);
+ } finally {
+ mDataStore.saveIfNeeded();
}
- String key = getLayoutDescriptor(device.getIdentifier());
- boolean changed = false;
- synchronized (mDataStore) {
- try {
- if (mDataStore.switchKeyboardLayout(key, handle)) {
- changed = true;
- }
- } finally {
- mDataStore.saveIfNeeded();
+ }
+
+ if (changed) {
+ if (mSwitchedKeyboardLayoutToast != null) {
+ mSwitchedKeyboardLayoutToast.cancel();
+ mSwitchedKeyboardLayoutToast = null;
+ }
+ if (keyboardLayoutDescriptor != null) {
+ KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
+ if (keyboardLayout != null) {
+ mSwitchedKeyboardLayoutToast = Toast.makeText(
+ mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
+ mSwitchedKeyboardLayoutToast.show();
}
}
- if (changed) {
- reloadKeyboardLayouts();
- }
+
+ reloadKeyboardLayouts();
}
}
}
@@ -1790,7 +1702,7 @@
}
@Override
- public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.println("INPUT MANAGER (dumpsys input)\n");
@@ -1798,49 +1710,8 @@
if (dumpStr != null) {
pw.println(dumpStr);
}
- pw.println(" Keyboard Layouts:");
- visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
- @Override
- public void visitKeyboardLayout(Resources resources,
- int keyboardLayoutResId, KeyboardLayout layout) {
- pw.println(" \"" + layout + "\": " + layout.getDescriptor());
- }
- });
- pw.println();
- synchronized(mDataStore) {
- mDataStore.dump(pw, " ");
- }
}
- @Override
- public void onShellCommand(FileDescriptor in, FileDescriptor out,
- FileDescriptor err, String[] args, ShellCallback callback,
- ResultReceiver resultReceiver) {
- (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
- }
-
- public int onShellCommand(Shell shell, String cmd) {
- if (TextUtils.isEmpty(cmd)) {
- shell.onHelp();
- return 1;
- }
- if (cmd.equals("setlayout")) {
- if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
- "onShellCommand()")) {
- throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
- }
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
- shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
- String descriptor = shell.getNextArgRequired();
- int vid = Integer.decode(shell.getNextArgRequired());
- int pid = Integer.decode(shell.getNextArgRequired());
- InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
- setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
- }
- return 0;
- }
-
-
private boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
@@ -2169,12 +2040,9 @@
case MSG_DELIVER_INPUT_DEVICES_CHANGED:
deliverInputDevicesChanged((InputDevice[])msg.obj);
break;
- case MSG_SWITCH_KEYBOARD_LAYOUT: {
- SomeArgs args = (SomeArgs)msg.obj;
- handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
- (InputMethodSubtypeHandle)args.arg2);
+ case MSG_SWITCH_KEYBOARD_LAYOUT:
+ handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
break;
- }
case MSG_RELOAD_KEYBOARD_LAYOUTS:
reloadKeyboardLayouts();
break;
@@ -2184,22 +2052,12 @@
case MSG_RELOAD_DEVICE_ALIASES:
reloadDeviceAliases();
break;
- case MSG_DELIVER_TABLET_MODE_CHANGED: {
+ case MSG_DELIVER_TABLET_MODE_CHANGED:
SomeArgs args = (SomeArgs) msg.obj;
long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
boolean inTabletMode = (boolean) args.arg1;
deliverTabletModeChanged(whenNanos, inTabletMode);
break;
- }
- case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
- final int userId = msg.arg1;
- final SomeArgs args = (SomeArgs) msg.obj;
- final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
- final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
- args.recycle();
- handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
- break;
- }
}
}
}
@@ -2341,25 +2199,6 @@
}
}
- private class Shell extends ShellCommand {
- @Override
- public int onCommand(String cmd) {
- return onShellCommand(this, cmd);
- }
-
- @Override
- public void onHelp() {
- final PrintWriter pw = getOutPrintWriter();
- pw.println("Input manager commands:");
- pw.println(" help");
- pw.println(" Print this help text.");
- pw.println("");
- pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
- + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
- pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
- }
- }
-
private final class LocalService extends InputManagerInternal {
@Override
public void setDisplayViewports(DisplayViewport defaultViewport,
@@ -2380,16 +2219,6 @@
}
@Override
- public void onInputMethodSubtypeChanged(int userId,
- @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
- final SomeArgs someArgs = SomeArgs.obtain();
- someArgs.arg1 = inputMethodInfo;
- someArgs.arg2 = subtype;
- mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
- .sendToTarget();
- }
-
- @Override
public void toggleCapsLock(int deviceId) {
nativeToggleCapsLock(mPtr, deviceId);
}
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index c9f8b20..196787a 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -16,7 +16,6 @@
package com.android.server.input;
-import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -28,8 +27,6 @@
import android.annotation.Nullable;
import android.view.Surface;
import android.hardware.input.TouchCalibration;
-import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
@@ -41,13 +38,10 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -139,26 +133,9 @@
}
return state.getKeyboardLayouts();
}
- public String getKeyboardLayout(String inputDeviceDescriptor,
- InputMethodSubtypeHandle imeHandle) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
- if (state == null) {
- return null;
- }
- return state.getKeyboardLayout(imeHandle);
- }
- public boolean setKeyboardLayout(String inputDeviceDescriptor,
- InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
- if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) {
- setDirty();
- return true;
- }
- return false;
- }
-
- public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) {
+ public boolean addKeyboardLayout(String inputDeviceDescriptor,
+ String keyboardLayoutDescriptor) {
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
setDirty();
@@ -177,10 +154,9 @@
return false;
}
- public boolean switchKeyboardLayout(String inputDeviceDescriptor,
- InputMethodSubtypeHandle imeHandle) {
+ public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
- if (state != null && state.switchKeyboardLayout(imeHandle)) {
+ if (state != null && state.switchKeyboardLayout(direction)) {
setDirty();
return true;
}
@@ -327,18 +303,6 @@
serializer.endDocument();
}
- public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "PersistentDataStore");
- pw.println(prefix + " mLoaded=" + mLoaded);
- pw.println(prefix + " mDirty=" + mDirty);
- pw.println(prefix + " InputDeviceStates:");
- int i = 0;
- for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
- pw.println(prefix + " " + i++ + ": " + entry.getKey());
- entry.getValue().dump(pw, prefix + " ");
- }
- }
-
private static final class InputDeviceState {
private static final String[] CALIBRATION_NAME = { "x_scale",
"x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };
@@ -346,8 +310,7 @@
private TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
@Nullable
private String mCurrentKeyboardLayout;
- private List<String> mUnassociatedKeyboardLayouts = new ArrayList<>();
- private ArrayMap<InputMethodSubtypeHandle, String> mKeyboardLayouts = new ArrayMap<>();
+ private ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
public TouchCalibration getTouchCalibration(int surfaceRotation) {
try {
@@ -386,34 +349,18 @@
}
public String[] getKeyboardLayouts() {
- if (mUnassociatedKeyboardLayouts.isEmpty()) {
+ if (mKeyboardLayouts.isEmpty()) {
return (String[])ArrayUtils.emptyArray(String.class);
}
- return mUnassociatedKeyboardLayouts.toArray(
- new String[mUnassociatedKeyboardLayouts.size()]);
- }
-
- public String getKeyboardLayout(InputMethodSubtypeHandle handle) {
- return mKeyboardLayouts.get(handle);
- }
-
- public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle,
- String keyboardLayout) {
- String existingLayout = mKeyboardLayouts.get(imeHandle);
- if (TextUtils.equals(existingLayout, keyboardLayout)) {
- return false;
- }
- mKeyboardLayouts.put(imeHandle, keyboardLayout);
- return true;
+ return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
}
public boolean addKeyboardLayout(String keyboardLayout) {
- int index = Collections.binarySearch(
- mUnassociatedKeyboardLayouts, keyboardLayout);
+ int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
if (index >= 0) {
return false;
}
- mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout);
+ mKeyboardLayouts.add(-index - 1, keyboardLayout);
if (mCurrentKeyboardLayout == null) {
mCurrentKeyboardLayout = keyboardLayout;
}
@@ -421,11 +368,11 @@
}
public boolean removeKeyboardLayout(String keyboardLayout) {
- int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout);
+ int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
if (index < 0) {
return false;
}
- mUnassociatedKeyboardLayouts.remove(index);
+ mKeyboardLayouts.remove(index);
updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
return true;
}
@@ -433,34 +380,41 @@
private void updateCurrentKeyboardLayoutIfRemoved(
String removedKeyboardLayout, int removedIndex) {
if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) {
- if (!mUnassociatedKeyboardLayouts.isEmpty()) {
+ if (!mKeyboardLayouts.isEmpty()) {
int index = removedIndex;
- if (index == mUnassociatedKeyboardLayouts.size()) {
+ if (index == mKeyboardLayouts.size()) {
index = 0;
}
- mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index);
+ mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
} else {
mCurrentKeyboardLayout = null;
}
}
}
- public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) {
- final String layout = mKeyboardLayouts.get(imeHandle);
- if (!TextUtils.equals(mCurrentKeyboardLayout, layout)) {
- mCurrentKeyboardLayout = layout;
- return true;
+ public boolean switchKeyboardLayout(int direction) {
+ final int size = mKeyboardLayouts.size();
+ if (size < 2) {
+ return false;
}
- return false;
+ int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
+ assert index >= 0;
+ if (direction > 0) {
+ index = (index + 1) % size;
+ } else {
+ index = (index + size - 1) % size;
+ }
+ mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
+ return true;
}
public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
boolean changed = false;
- for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) {
- String keyboardLayout = mUnassociatedKeyboardLayouts.get(i);
+ for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
+ String keyboardLayout = mKeyboardLayouts.get(i);
if (!availableKeyboardLayouts.contains(keyboardLayout)) {
Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
- mUnassociatedKeyboardLayouts.remove(i);
+ mKeyboardLayouts.remove(i);
updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
changed = true;
}
@@ -478,8 +432,13 @@
throw new XmlPullParserException(
"Missing descriptor attribute on keyboard-layout.");
}
-
String current = parser.getAttributeValue(null, "current");
+ if (mKeyboardLayouts.contains(descriptor)) {
+ throw new XmlPullParserException(
+ "Found duplicate keyboard layout.");
+ }
+
+ mKeyboardLayouts.add(descriptor);
if (current != null && current.equals("true")) {
if (mCurrentKeyboardLayout != null) {
throw new XmlPullParserException(
@@ -487,32 +446,6 @@
}
mCurrentKeyboardLayout = descriptor;
}
-
- String inputMethodId = parser.getAttributeValue(null, "input-method-id");
- String inputMethodSubtypeId =
- parser.getAttributeValue(null, "input-method-subtype-id");
- if (inputMethodId == null && inputMethodSubtypeId != null
- || inputMethodId != null && inputMethodSubtypeId == null) {
- throw new XmlPullParserException(
- "Found an incomplete input method description");
- }
-
- if (inputMethodSubtypeId != null) {
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
- inputMethodId, Integer.parseInt(inputMethodSubtypeId));
- if (mKeyboardLayouts.containsKey(handle)) {
- throw new XmlPullParserException(
- "Found duplicate subtype to keyboard layout mapping: "
- + handle);
- }
- mKeyboardLayouts.put(handle, descriptor);
- } else {
- if (mUnassociatedKeyboardLayouts.contains(descriptor)) {
- throw new XmlPullParserException(
- "Found duplicate unassociated keyboard layout: " + descriptor);
- }
- mUnassociatedKeyboardLayouts.add(descriptor);
- }
} else if (parser.getName().equals("calibration")) {
String format = parser.getAttributeValue(null, "format");
String rotation = parser.getAttributeValue(null, "rotation");
@@ -563,31 +496,19 @@
}
// Maintain invariant that layouts are sorted.
- Collections.sort(mUnassociatedKeyboardLayouts);
+ Collections.sort(mKeyboardLayouts);
// Maintain invariant that there is always a current keyboard layout unless
// there are none installed.
- if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) {
- mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0);
+ if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
+ mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
}
}
public void saveToXml(XmlSerializer serializer) throws IOException {
- for (String layout : mUnassociatedKeyboardLayouts) {
+ for (String layout : mKeyboardLayouts) {
serializer.startTag(null, "keyboard-layout");
serializer.attribute(null, "descriptor", layout);
- serializer.endTag(null, "keyboard-layout");
- }
-
- final int N = mKeyboardLayouts.size();
- for (int i = 0; i < N; i++) {
- final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i);
- final String layout = mKeyboardLayouts.valueAt(i);
- serializer.startTag(null, "keyboard-layout");
- serializer.attribute(null, "descriptor", layout);
- serializer.attribute(null, "input-method-id", handle.getInputMethodId());
- serializer.attribute(null, "input-method-subtype-id",
- Integer.toString(handle.getSubtypeId()));
if (layout.equals(mCurrentKeyboardLayout)) {
serializer.attribute(null, "current", "true");
}
@@ -612,22 +533,6 @@
}
}
- private void dump(final PrintWriter pw, final String prefix) {
- pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout);
- pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts);
- pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration));
- pw.println(prefix + "Subtype to Layout Mappings:");
- final int N = mKeyboardLayouts.size();
- if (N != 0) {
- for (int i = 0; i < N; i++) {
- pw.println(prefix + " " + mKeyboardLayouts.keyAt(i) + ": "
- + mKeyboardLayouts.valueAt(i));
- }
- } else {
- pw.println(prefix + " <none>");
- }
- }
-
private static String surfaceRotationToString(int surfaceRotation) {
switch (surfaceRotation) {
case Surface.ROTATION_0: return "0";
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java
index 08607bc..425ec47 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -48,6 +48,11 @@
public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket);
/**
+ * Tell the scheduler when a JobServiceContext starts running a job in an app
+ */
+ void noteJobStart(String packageName, int userId);
+
+ /**
* Returns a list of pending jobs scheduled by the system service.
*/
List<JobInfo> getSystemScheduledPendingJobs();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 0e7e540..0b1f9a6 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -88,7 +88,6 @@
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob;
-import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
import com.android.server.job.controllers.ConnectivityController;
@@ -109,6 +108,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
@@ -239,6 +239,27 @@
long mHeartbeat = 0;
long mLastHeartbeatTime = sElapsedRealtimeClock.millis();
+ /**
+ * Named indices into the STANDBY_BEATS array, for clarity in referring to
+ * specific buckets' bookkeeping.
+ */
+ static final int ACTIVE_INDEX = 0;
+ static final int WORKING_INDEX = 1;
+ static final int FREQUENT_INDEX = 2;
+ static final int RARE_INDEX = 3;
+
+ /**
+ * Bookkeeping about when jobs last run. We keep our own record in heartbeat time,
+ * rather than rely on Usage Stats' timestamps, because heartbeat time can be
+ * manipulated for testing purposes and we need job runnability to track that rather
+ * than real time.
+ *
+ * Outer SparseArray slices by user handle; inner map of package name to heartbeat
+ * is a HashMap<> rather than ArrayMap<> because we expect O(hundreds) of keys
+ * and it will be accessed in a known-hot code path.
+ */
+ final SparseArray<HashMap<String, Long>> mLastJobHeartbeats = new SparseArray<>();
+
static final String HEARTBEAT_TAG = "*job.heartbeat*";
final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener();
@@ -533,11 +554,11 @@
DEFAULT_MIN_EXP_BACKOFF_TIME);
STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME,
DEFAULT_STANDBY_HEARTBEAT_TIME);
- STANDBY_BEATS[1] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
+ STANDBY_BEATS[WORKING_INDEX] = mParser.getInt(KEY_STANDBY_WORKING_BEATS,
DEFAULT_STANDBY_WORKING_BEATS);
- STANDBY_BEATS[2] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
+ STANDBY_BEATS[FREQUENT_INDEX] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS,
DEFAULT_STANDBY_FREQUENT_BEATS);
- STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
+ STANDBY_BEATS[RARE_INDEX] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
DEFAULT_STANDBY_RARE_BEATS);
CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC,
DEFAULT_CONN_CONGESTION_DELAY_FRAC);
@@ -1051,7 +1072,8 @@
final JobStatus job = jsc.getRunningJobLocked();
if (job != null
&& (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
- && !job.dozeWhitelisted) {
+ && !job.dozeWhitelisted
+ && !job.uidActive) {
// We will report active if we have a job running and it is not an exception
// due to being in the foreground or whitelisted.
active = true;
@@ -1115,7 +1137,6 @@
mStorageController = new StorageController(this);
mControllers.add(mStorageController);
mControllers.add(new BackgroundJobsController(this));
- mControllers.add(new AppIdleController(this));
mControllers.add(new ContentObserverController(this));
mDeviceIdleJobsController = new DeviceIdleJobsController(this);
mControllers.add(mDeviceIdleJobsController);
@@ -1421,15 +1442,40 @@
periodicToReschedule.getLastFailedRunTime());
}
+ /*
+ * We default to "long enough ago that every bucket's jobs are immediately runnable" to
+ * avoid starvation of apps in uncommon-use buckets that might arise from repeated
+ * reboot behavior.
+ */
long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) {
- final long heartbeat;
- final long timeSinceLastJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+ // The furthest back in pre-boot time that we need to bother with
+ long heartbeat = -mConstants.STANDBY_BEATS[RARE_INDEX];
+ boolean cacheHit = false;
synchronized (mLock) {
- heartbeat = mHeartbeat - (timeSinceLastJob / mConstants.STANDBY_HEARTBEAT_TIME);
+ HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId);
+ if (jobPackages != null) {
+ long cachedValue = jobPackages.getOrDefault(packageName, Long.MAX_VALUE);
+ if (cachedValue < Long.MAX_VALUE) {
+ cacheHit = true;
+ heartbeat = cachedValue;
+ }
+ }
+ if (!cacheHit) {
+ // We haven't seen it yet; ask usage stats about it
+ final long timeSinceJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+ if (timeSinceJob < Long.MAX_VALUE) {
+ // Usage stats knows about it from before, so calculate back from that
+ // and go from there.
+ heartbeat = mHeartbeat - (timeSinceJob / mConstants.STANDBY_HEARTBEAT_TIME);
+ }
+ // If usage stats returned its "not found" MAX_VALUE, we still have the
+ // negative default 'heartbeat' value we established above
+ setLastJobHeartbeatLocked(packageName, userId, heartbeat);
+ }
}
if (DEBUG_STANDBY) {
- Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " + packageName + "/" + userId
- + " delta=" + timeSinceLastJob);
+ Slog.v(TAG, "Last job heartbeat " + heartbeat + " for "
+ + packageName + "/" + userId);
}
return heartbeat;
}
@@ -1438,12 +1484,21 @@
return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId());
}
+ void setLastJobHeartbeatLocked(String packageName, int userId, long heartbeat) {
+ HashMap<String, Long> jobPackages = mLastJobHeartbeats.get(userId);
+ if (jobPackages == null) {
+ jobPackages = new HashMap<>();
+ mLastJobHeartbeats.put(userId, jobPackages);
+ }
+ jobPackages.put(packageName, heartbeat);
+ }
+
// JobCompletedListener implementations.
/**
* A job just finished executing. We fetch the
* {@link com.android.server.job.controllers.JobStatus} from the store and depending on
- * whether we want to reschedule we readd it to the controllers.
+ * whether we want to reschedule we re-add it to the controllers.
* @param jobStatus Completed job.
* @param needsReschedule Whether the implementing class should reschedule this job.
*/
@@ -1867,6 +1922,9 @@
// scheduled are sitting there, not ready yet) and very cheap to check (just
// a few conditions on data in JobStatus).
if (!jobReady) {
+ if (job.getSourcePackageName().equals("android.jobscheduler.cts.jobtestapp")) {
+ Slog.v(TAG, " NOT READY: " + job);
+ }
return false;
}
@@ -1905,9 +1963,21 @@
// an appropriate amount of time since the last invocation. During device-
// wide parole, standby bucketing is ignored.
//
- // But if a job has FLAG_EXEMPT_FROM_APP_STANDBY, don't check it.
- if (!mInParole && !job.getJob().isExemptedFromAppStandby()) {
+ // Jobs in 'active' apps are not subject to standby, nor are jobs that are
+ // specifically marked as exempt.
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+ + " parole=" + mInParole + " active=" + job.uidActive
+ + " exempt=" + job.getJob().isExemptedFromAppStandby());
+ }
+ if (!mInParole
+ && !job.uidActive
+ && !job.getJob().isExemptedFromAppStandby()) {
final int bucket = job.getStandbyBucket();
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, " bucket=" + bucket + " heartbeat=" + mHeartbeat
+ + " next=" + mNextBucketHeartbeat[bucket]);
+ }
if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
// Only skip this job if the app is still waiting for the end of its nominal
// bucket interval. Once it's waited that long, we let it go ahead and clear.
@@ -2194,6 +2264,12 @@
return baseHeartbeat;
}
+ public void noteJobStart(String packageName, int userId) {
+ synchronized (mLock) {
+ setLastJobHeartbeatLocked(packageName, userId, mHeartbeat);
+ }
+ }
+
/**
* Returns a list of all pending jobs. A running job is not considered pending. Periodic
* jobs are always considered pending.
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 1f8cf76..0bb6854 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -268,10 +268,14 @@
} catch (RemoteException e) {
// Whatever.
}
+ final String jobPackage = job.getSourcePackageName();
+ final int jobUserId = job.getSourceUserId();
UsageStatsManagerInternal usageStats =
LocalServices.getService(UsageStatsManagerInternal.class);
- usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(),
- mExecutionStartTimeElapsed);
+ usageStats.setLastJobRunTime(jobPackage, jobUserId, mExecutionStartTimeElapsed);
+ JobSchedulerInternal jobScheduler =
+ LocalServices.getService(JobSchedulerInternal.class);
+ jobScheduler.noteJobStart(jobPackage, jobUserId);
mAvailable = false;
mStoppedReason = null;
mStoppedTime = 0;
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
deleted file mode 100644
index ed29a4c..0000000
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * 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
- */
-
-package com.android.server.job.controllers;
-
-import android.app.usage.UsageStatsManagerInternal;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerService;
-import com.android.server.job.StateControllerProto;
-
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
-/**
- * Controls when apps are considered idle and if jobs pertaining to those apps should
- * be executed. Apps that haven't been actively launched or accessed from a foreground app
- * for a certain amount of time (maybe hours or days) are considered idle. When the app comes
- * out of idle state, it will be allowed to run scheduled jobs.
- */
-public final class AppIdleController extends StateController {
- private static final String TAG = "JobScheduler.AppIdle";
- private static final boolean DEBUG = JobSchedulerService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- private final UsageStatsManagerInternal mUsageStatsInternal;
- private boolean mInitializedParoleOn;
- boolean mAppIdleParoleOn;
-
- final class GlobalUpdateFunc implements Consumer<JobStatus> {
- boolean mChanged;
-
- @Override
- public void accept(JobStatus jobStatus) {
- String packageName = jobStatus.getSourcePackageName();
- final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- jobStatus.getSourceUid(), jobStatus.getSourceUserId());
- if (DEBUG) {
- Slog.d(TAG, "Setting idle state of " + packageName + " to " + appIdle);
- }
- if (jobStatus.setAppNotIdleConstraintSatisfied(!appIdle)) {
- mChanged = true;
- }
- }
- }
-
- final static class PackageUpdateFunc implements Consumer<JobStatus> {
- final int mUserId;
- final String mPackage;
- final boolean mIdle;
- boolean mChanged;
-
- PackageUpdateFunc(int userId, String pkg, boolean idle) {
- mUserId = userId;
- mPackage = pkg;
- mIdle = idle;
- }
-
- @Override
- public void accept(JobStatus jobStatus) {
- if (jobStatus.getSourcePackageName().equals(mPackage)
- && jobStatus.getSourceUserId() == mUserId) {
- if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) {
- if (DEBUG) {
- Slog.d(TAG, "App Idle state changed, setting idle state of "
- + mPackage + " to " + mIdle);
- }
- mChanged = true;
- }
- }
- }
- }
-
- public AppIdleController(JobSchedulerService service) {
- super(service);
- mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
- mAppIdleParoleOn = true;
- mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
- }
-
- @Override
- public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- if (!mInitializedParoleOn) {
- mInitializedParoleOn = true;
- mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
- }
- String packageName = jobStatus.getSourcePackageName();
- final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- jobStatus.getSourceUid(), jobStatus.getSourceUserId());
- if (DEBUG) {
- Slog.d(TAG, "Start tracking, setting idle state of "
- + packageName + " to " + appIdle);
- }
- jobStatus.setAppNotIdleConstraintSatisfied(!appIdle);
- }
-
- @Override
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
- }
-
- @Override
- public void dumpControllerStateLocked(final IndentingPrintWriter pw,
- final Predicate<JobStatus> predicate) {
- pw.println("Parole on: " + mAppIdleParoleOn);
- pw.println();
-
- mService.getJobStore().forEachJob(predicate, (jobStatus) -> {
- pw.print("#");
- jobStatus.printUniqueId(pw);
- pw.print(" from ");
- UserHandle.formatUid(pw, jobStatus.getSourceUid());
- pw.print(": ");
- pw.print(jobStatus.getSourcePackageName());
- if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) {
- pw.println(" RUNNABLE");
- } else {
- pw.println(" WAITING");
- }
- });
- }
-
- @Override
- public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
- Predicate<JobStatus> predicate) {
- final long token = proto.start(fieldId);
- final long mToken = proto.start(StateControllerProto.APP_IDLE);
-
- proto.write(StateControllerProto.AppIdleController.IS_PAROLE_ON, mAppIdleParoleOn);
-
- mService.getJobStore().forEachJob(predicate, (js) -> {
- final long jsToken =
- proto.start(StateControllerProto.AppIdleController.TRACKED_JOBS);
- js.writeToShortProto(proto, StateControllerProto.AppIdleController.TrackedJob.INFO);
- proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_UID,
- js.getSourceUid());
- proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_PACKAGE_NAME,
- js.getSourcePackageName());
- proto.write(
- StateControllerProto.AppIdleController.TrackedJob.ARE_CONSTRAINTS_SATISFIED,
- (js.satisfiedConstraints & JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
- proto.end(jsToken);
- });
-
- proto.end(mToken);
- proto.end(token);
- }
-
- void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
- // Flag if any app's idle state has changed
- boolean changed = false;
- synchronized (mLock) {
- if (mAppIdleParoleOn == isAppIdleParoleOn) {
- return;
- }
- mAppIdleParoleOn = isAppIdleParoleOn;
- GlobalUpdateFunc update = new GlobalUpdateFunc();
- mService.getJobStore().forEachJob(update);
- if (update.mChanged) {
- changed = true;
- }
- }
- if (changed) {
- mStateChangedListener.onControllerStateChanged();
- }
- }
-
- private final class AppIdleStateChangeListener
- extends UsageStatsManagerInternal.AppIdleStateChangeListener {
- @Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket,
- int reason) {
- boolean changed = false;
- synchronized (mLock) {
- if (mAppIdleParoleOn) {
- return;
- }
-
- PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle);
- mService.getJobStore().forEachJob(update);
- if (update.mChanged) {
- changed = true;
- }
- }
- if (changed) {
- mStateChangedListener.onControllerStateChanged();
- }
- }
-
- @Override
- public void onParoleStateChanged(boolean isParoleOn) {
- if (DEBUG) {
- Slog.d(TAG, "Parole on: " + isParoleOn);
- }
- setAppIdleParoleOn(isParoleOn);
- }
- }
-}
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 36e7511..b698e5b 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -28,17 +28,32 @@
import com.android.server.AppStateTracker.Listener;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
import com.android.server.job.StateControllerProto;
import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob;
import java.util.function.Consumer;
import java.util.function.Predicate;
+/**
+ * Tracks the following pieces of JobStatus state:
+ *
+ * - the CONSTRAINT_BACKGROUND_NOT_RESTRICTED general constraint bit, which
+ * is used to selectively permit battery-saver exempted jobs to run; and
+ *
+ * - the uid-active boolean state expressed by the AppStateTracker. Jobs in 'active'
+ * uids are inherently eligible to run jobs regardless of the uid's standby bucket.
+ */
public final class BackgroundJobsController extends StateController {
private static final String TAG = "JobScheduler.Background";
private static final boolean DEBUG = JobSchedulerService.DEBUG
|| Log.isLoggable(TAG, Log.DEBUG);
+ // Tri-state about possible "is this uid 'active'?" knowledge
+ static final int UNKNOWN = 0;
+ static final int KNOWN_ACTIVE = 1;
+ static final int KNOWN_INACTIVE = 2;
+
private final AppStateTracker mAppStateTracker;
public BackgroundJobsController(JobSchedulerService service) {
@@ -51,7 +66,7 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- updateSingleJobRestrictionLocked(jobStatus);
+ updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
}
@Override
@@ -137,23 +152,24 @@
}
private void updateAllJobRestrictionsLocked() {
- updateJobRestrictionsLocked(/*filterUid=*/ -1);
+ updateJobRestrictionsLocked(/*filterUid=*/ -1, UNKNOWN);
}
- private void updateJobRestrictionsForUidLocked(int uid) {
-
- // TODO Use forEachJobForSourceUid() once we have it.
-
- updateJobRestrictionsLocked(/*filterUid=*/ uid);
+ private void updateJobRestrictionsForUidLocked(int uid, boolean isActive) {
+ updateJobRestrictionsLocked(uid, (isActive) ? KNOWN_ACTIVE : KNOWN_INACTIVE);
}
- private void updateJobRestrictionsLocked(int filterUid) {
- final UpdateJobFunctor updateTrackedJobs =
- new UpdateJobFunctor(filterUid);
+ private void updateJobRestrictionsLocked(int filterUid, int newActiveState) {
+ final UpdateJobFunctor updateTrackedJobs = new UpdateJobFunctor(newActiveState);
final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
- mService.getJobStore().forEachJob(updateTrackedJobs);
+ final JobStore store = mService.getJobStore();
+ if (filterUid > 0) {
+ store.forEachJobForSourceUid(filterUid, updateTrackedJobs);
+ } else {
+ store.forEachJob(updateTrackedJobs);
+ }
final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
if (DEBUG) {
@@ -170,7 +186,7 @@
}
}
- boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
+ boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, int activeState) {
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
@@ -179,28 +195,32 @@
(jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
!= 0);
- return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
+ final boolean isActive;
+ if (activeState == UNKNOWN) {
+ isActive = mAppStateTracker.isUidActive(uid);
+ } else {
+ isActive = (activeState == KNOWN_ACTIVE);
+ }
+ boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
+ didChange |= jobStatus.setUidActive(isActive);
+ return didChange;
}
private final class UpdateJobFunctor implements Consumer<JobStatus> {
- private final int mFilterUid;
-
+ final int activeState;
boolean mChanged = false;
int mTotalCount = 0;
int mCheckedCount = 0;
- UpdateJobFunctor(int filterUid) {
- mFilterUid = filterUid;
+ public UpdateJobFunctor(int newActiveState) {
+ activeState = newActiveState;
}
@Override
public void accept(JobStatus jobStatus) {
mTotalCount++;
- if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) {
- return;
- }
mCheckedCount++;
- if (updateSingleJobRestrictionLocked(jobStatus)) {
+ if (updateSingleJobRestrictionLocked(jobStatus, activeState)) {
mChanged = true;
}
}
@@ -215,16 +235,16 @@
}
@Override
- public void updateJobsForUid(int uid) {
+ public void updateJobsForUid(int uid, boolean isActive) {
synchronized (mLock) {
- updateJobRestrictionsForUidLocked(uid);
+ updateJobRestrictionsForUidLocked(uid, isActive);
}
}
@Override
- public void updateJobsForUidPackage(int uid, String packageName) {
+ public void updateJobsForUidPackage(int uid, String packageName, boolean isActive) {
synchronized (mLock) {
- updateJobRestrictionsForUidLocked(uid);
+ updateJobRestrictionsForUidLocked(uid, isActive);
}
}
};
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 5616197..578a32c 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -73,7 +73,6 @@
static final int CONSTRAINT_TIMING_DELAY = 1<<31;
static final int CONSTRAINT_DEADLINE = 1<<30;
static final int CONSTRAINT_CONNECTIVITY = 1<<28;
- static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
@@ -153,6 +152,9 @@
// Set to true if doze constraint was satisfied due to app being whitelisted.
public boolean dozeWhitelisted;
+ // Set to true when the app is "active" per AppStateTracker
+ public boolean uidActive;
+
/**
* Flag for {@link #trackingControllers}: the battery controller is currently tracking this job.
*/
@@ -838,10 +840,6 @@
return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
}
- boolean setAppNotIdleConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
- }
-
boolean setContentTriggerConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
}
@@ -855,6 +853,14 @@
return setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state);
}
+ boolean setUidActive(final boolean newActiveState) {
+ if (newActiveState != uidActive) {
+ uidActive = newActiveState;
+ return true;
+ }
+ return false; /* unchanged */
+ }
+
boolean setConstraintSatisfied(int constraint, boolean state) {
boolean old = (satisfiedConstraints&constraint) != 0;
if (old == state) {
@@ -904,13 +910,11 @@
// NotRestrictedInBackground implicit constraint must be satisfied
final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
&& (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
- final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
|| (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
final boolean notRestrictedInBg =
(satisfiedConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0;
- return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing
- && notRestrictedInBg;
+ return (isConstraintsSatisfied() || deadlineSatisfied) && notDozing && notRestrictedInBg;
}
static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
@@ -990,9 +994,6 @@
if (job.isPersisted()) {
sb.append(" PERSISTED");
}
- if ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) == 0) {
- sb.append(" WAIT:APP_NOT_IDLE");
- }
if ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) == 0) {
sb.append(" WAIT:DEV_NOT_DOZING");
}
@@ -1091,9 +1092,6 @@
if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
pw.print(" CONNECTIVITY");
}
- if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
- pw.print(" APP_NOT_IDLE");
- }
if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
pw.print(" CONTENT_TRIGGER");
}
@@ -1133,9 +1131,6 @@
if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONNECTIVITY);
}
- if ((constraints & CONSTRAINT_APP_NOT_IDLE) != 0) {
- proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_APP_NOT_IDLE);
- }
if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONTENT_TRIGGER);
}
@@ -1307,6 +1302,9 @@
if (dozeWhitelisted) {
pw.print(prefix); pw.println("Doze whitelisted: true");
}
+ if (uidActive) {
+ pw.print(prefix); pw.println("Uid: active");
+ }
}
if (trackingControllers != 0) {
pw.print(prefix); pw.print("Tracking:");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a572cdf..74ebf3e4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -102,6 +102,7 @@
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -436,6 +437,8 @@
mStrongAuthTracker.register(mStrongAuth);
mSpManager = injector.getSyntheticPasswordManager(mStorage);
+
+ LocalServices.addService(LockSettingsInternal.class, new LocalService());
}
/**
@@ -1041,14 +1044,10 @@
private boolean isUserSecure(int userId) {
synchronized (mSpManager) {
- try {
- if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- long handle = getSyntheticPasswordHandleLocked(userId);
- return mSpManager.getCredentialType(handle, userId) !=
- LockPatternUtils.CREDENTIAL_TYPE_NONE;
- }
- } catch (RemoteException e) {
- // fall through
+ if (isSyntheticPasswordBasedCredentialLocked(userId)) {
+ long handle = getSyntheticPasswordHandleLocked(userId);
+ return mSpManager.getCredentialType(handle, userId) !=
+ LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
}
return mStorage.hasCredential(userId);
@@ -2098,7 +2097,6 @@
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
- LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
LockPatternUtils.PASSWORD_TYPE_KEY,
LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
@@ -2306,7 +2304,7 @@
SyntheticPasswordManager.DEFAULT_HANDLE, userId);
}
- private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
+ private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
if (userId == USER_FRP) {
final int type = mStorage.readPersistentDataBlock().type;
return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
@@ -2319,7 +2317,7 @@
}
@VisibleForTesting
- protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
+ protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
long handle = getSyntheticPasswordHandleLocked(userId);
// This is a global setting
long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
@@ -2327,7 +2325,7 @@
return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
}
- private void enableSyntheticPasswordLocked() throws RemoteException {
+ private void enableSyntheticPasswordLocked() {
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
@@ -2526,9 +2524,7 @@
mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
}
- @Override
- public long addEscrowToken(byte[] token, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private long addEscrowToken(byte[] token, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
synchronized (mSpManager) {
enableSyntheticPasswordLocked();
@@ -2560,7 +2556,7 @@
}
}
- private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
+ private void activateEscrowTokens(AuthenticationToken auth, int userId) {
if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
synchronized (mSpManager) {
disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
@@ -2571,17 +2567,13 @@
}
}
- @Override
- public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private boolean isEscrowTokenActive(long handle, int userId) {
synchronized (mSpManager) {
return mSpManager.existsHandle(handle, userId);
}
}
- @Override
- public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private boolean removeEscrowToken(long handle, int userId) {
synchronized (mSpManager) {
if (handle == getSyntheticPasswordHandleLocked(userId)) {
Slog.w(TAG, "Cannot remove password handle");
@@ -2599,10 +2591,8 @@
}
}
- @Override
- public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
byte[] token, int requestedQuality, int userId) throws RemoteException {
- ensureCallerSystemUid();
boolean result;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2651,10 +2641,8 @@
return true;
}
- @Override
- public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
+ private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
throws RemoteException {
- ensureCallerSystemUid();
AuthenticationResult authResult;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2664,11 +2652,12 @@
tokenHandle, token, userId);
if (authResult.authToken == null) {
Slog.w(TAG, "Invalid escrow token supplied");
- return;
+ return false;
}
}
unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
onAuthTokenKnownForUser(userId, authResult.authToken);
+ return true;
}
@Override
@@ -2733,20 +2722,11 @@
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
mSpManager.destroyEscrowData(userId);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private void ensureCallerSystemUid() throws SecurityException {
- final int callingUid = mInjector.binderGetCallingUid();
- if (callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("Only system can call this API.");
- }
- }
-
private class DeviceProvisionedObserver extends ContentObserver {
private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
Settings.Global.DEVICE_PROVISIONED);
@@ -2835,4 +2815,46 @@
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
}
+
+ private final class LocalService extends LockSettingsInternal {
+
+ @Override
+ public long addEscrowToken(byte[] token, int userId) {
+ try {
+ return LockSettingsService.this.addEscrowToken(token, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean removeEscrowToken(long handle, int userId) {
+ return LockSettingsService.this.removeEscrowToken(handle, userId);
+ }
+
+ @Override
+ public boolean isEscrowTokenActive(long handle, int userId) {
+ return LockSettingsService.this.isEscrowTokenActive(handle, userId);
+ }
+
+ @Override
+ public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ byte[] token, int requestedQuality, int userId) {
+ try {
+ return LockSettingsService.this.setLockCredentialWithToken(credential, type,
+ tokenHandle, token, requestedQuality, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+ try {
+ return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 6939537..3b5b1bf 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -2086,7 +2086,7 @@
public SessionTokensListenerRecord(ISessionTokensListener listener, int userId) {
mListener = listener;
- // TODO should userId be mapped through mFullUserIds? (b/73597722)
+ // TODO(jaewan): should userId be mapped through mFullUserIds? (b/73597722)
mUserId = userId;
}
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index e5fc6e5..6907c58 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -39,6 +39,7 @@
import com.android.internal.net.INetworkWatchlistManager;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.net.BaseNetdEventCallback;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -139,7 +140,7 @@
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
- private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+ private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
@Override
public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
long timestamp, int uid) {
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index d8a30ae..d91d541 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -15,6 +15,8 @@
*/
package com.android.server.notification;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+
import android.content.Context;
import android.util.Slog;
@@ -54,6 +56,11 @@
}
}
+ if (record.isIntercepted()
+ && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_BADGE) != 0) {
+ record.setShowBadge(false);
+ }
+
return null;
}
@@ -64,6 +71,5 @@
@Override
public void setZenHelper(ZenModeHelper helper) {
-
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cd387b0..b68b98d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -22,6 +22,16 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -60,8 +70,6 @@
import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -1342,6 +1350,7 @@
@Override
void onPolicyChanged() {
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
+ mRankingHandler.requestSort();
}
});
mRankingHelper = new RankingHelper(getContext(),
@@ -1781,6 +1790,74 @@
UsageEvents.Event.NOTIFICATION_SEEN);
}
+ protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
+ int targetSdkVersion) {
+ if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
+ return incomingPolicy.suppressedVisualEffects;
+ }
+ final int[] effectsIntroducedInP = {
+ SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+ SUPPRESSED_EFFECT_LIGHTS,
+ SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_STATUS_BAR,
+ SUPPRESSED_EFFECT_BADGE,
+ SUPPRESSED_EFFECT_AMBIENT,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST
+ };
+
+ int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
+ if (targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
+ // unset higher order bits introduced in P, maintain the user's higher order bits
+ for (int i = 0; i < effectsIntroducedInP.length ; i++) {
+ newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
+ newSuppressedVisualEffects |=
+ (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
+ }
+ // set higher order bits according to lower order bits
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+ }
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+ }
+ } else {
+ boolean hasNewEffects = (newSuppressedVisualEffects
+ - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
+ // if any of the new effects introduced in P are set
+ if (hasNewEffects) {
+ // clear out the deprecated effects
+ newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
+ | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+ // set the deprecated effects according to the new more specific effects
+ if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
+ }
+ if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
+ && (newSuppressedVisualEffects
+ & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
+ && (newSuppressedVisualEffects
+ & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
+ }
+ } else {
+ // set higher order bits according to lower order bits
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+ }
+ if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
+ newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+ }
+ }
+ }
+
+ return newSuppressedVisualEffects;
+ }
+
/**
* Report to usage stats that the notification was clicked.
* @param r notification record
@@ -3063,10 +3140,9 @@
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
0, UserHandle.getUserId(MY_UID));
+ Policy currPolicy = mZenModeHelper.getNotificationPolicy();
if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
- Policy currPolicy = mZenModeHelper.getNotificationPolicy();
-
int priorityCategories = policy.priorityCategories;
// ignore alarm and media values from new policy
priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
@@ -3084,11 +3160,13 @@
policy.priorityCallSenders, policy.priorityMessageSenders,
policy.suppressedVisualEffects);
}
+ int newVisualEffects = calculateSuppressedVisualEffects(
+ policy, currPolicy, applicationInfo.targetSdkVersion);
+ policy = new Policy(policy.priorityCategories,
+ policy.priorityCallSenders, policy.priorityMessageSenders,
+ newVisualEffects);
- Slog.i(TAG, "setNotificationPolicy pkg=" + pkg
- + " targetSdk=" + applicationInfo.targetSdkVersion
- + " policy="
- + Policy.priorityCategoriesToString(policy.priorityCategories));
+ ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
mZenModeHelper.setNotificationPolicy(policy);
} catch (RemoteException e) {
} finally {
@@ -4465,8 +4543,7 @@
// release the light
boolean wasShowLights = mLights.remove(key);
if (record.getLight() != null && aboveThreshold
- && ((record.getSuppressedVisualEffects()
- & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
+ && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
mLights.add(key);
updateLightsLocked();
if (mUseAttentionLight) {
@@ -4864,11 +4941,8 @@
private void applyZenModeLocked(NotificationRecord record) {
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
if (record.isIntercepted()) {
- int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
- ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
- | (mZenModeHelper.shouldSuppressWhenScreenOn()
- ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
- record.setSuppressedVisualEffects(suppressed);
+ record.setSuppressedVisualEffects(
+ mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
} else {
record.setSuppressedVisualEffects(0);
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 8d2f0dd..4404c48 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -712,13 +712,8 @@
return Objects.equals(getNotification().category, category);
}
- public boolean isAudioStream(int stream) {
- return getNotification().audioStreamType == stream;
- }
-
public boolean isAudioAttributesUsage(int usage) {
- final AudioAttributes attributes = getNotification().audioAttributes;
- return attributes != null && attributes.getUsage() == usage;
+ return mAttributes != null && mAttributes.getUsage() == usage;
}
/**
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index f7efff0f..6760875 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.media.AudioManager;
import android.net.Uri;
@@ -60,6 +61,7 @@
private static final int TYPE_DISABLE_EFFECTS = 13;
private static final int TYPE_SUPPRESSOR_CHANGED = 14;
private static final int TYPE_LISTENER_HINTS_CHANGED = 15;
+ private static final int TYPE_SET_NOTIFICATION_POLICY = 16;
private static int sNext;
private static int sSize;
@@ -108,6 +110,12 @@
append(TYPE_EXIT_CONDITION, c + "," + componentToString(component) + "," + reason);
}
+ public static void traceSetNotificationPolicy(String pkg, int targetSdk,
+ NotificationManager.Policy policy) {
+ append(TYPE_SET_NOTIFICATION_POLICY, "pkg=" + pkg + " targetSdk=" + targetSdk
+ + " NotificationPolicy=" + policy.toString());
+ }
+
public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
append(TYPE_SUBSCRIBE, uri + "," + subscribeResult(provider, e));
}
@@ -160,6 +168,7 @@
case TYPE_DISABLE_EFFECTS: return "disable_effects";
case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed";
case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
+ case TYPE_SET_NOTIFICATION_POLICY: return "set_notification_policy";
default: return "unknown";
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeExtractor.java b/services/core/java/com/android/server/notification/ZenModeExtractor.java
index 74f9806..a0aa1c3 100644
--- a/services/core/java/com/android/server/notification/ZenModeExtractor.java
+++ b/services/core/java/com/android/server/notification/ZenModeExtractor.java
@@ -16,8 +16,8 @@
package com.android.server.notification;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import android.content.Context;
import android.util.Log;
@@ -49,11 +49,8 @@
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
if (record.isIntercepted()) {
- int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
- ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
- | (mZenModeHelper.shouldSuppressWhenScreenOn()
- ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
- record.setSuppressedVisualEffects(suppressed);
+ record.setSuppressedVisualEffects(
+ mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
} else {
record.setSuppressedVisualEffects(0);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index a0003a5..71cee05 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -16,7 +16,10 @@
package com.android.server.notification;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+
import android.app.Notification;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.media.AudioAttributes;
@@ -30,6 +33,9 @@
import android.util.ArrayMap;
import android.util.Slog;
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.util.NotificationMessagingUtil;
+
import java.io.PrintWriter;
import java.util.Date;
import java.util.Objects;
@@ -43,9 +49,16 @@
private final Context mContext;
private ComponentName mDefaultPhoneApp;
+ private final NotificationMessagingUtil mMessagingUtil;
public ZenModeFiltering(Context context) {
mContext = context;
+ mMessagingUtil = new NotificationMessagingUtil(mContext);
+ }
+
+ public ZenModeFiltering(Context context, NotificationMessagingUtil messagingUtil) {
+ mContext = context;
+ mMessagingUtil = messagingUtil;
}
public void dump(PrintWriter pw, String prefix) {
@@ -104,6 +117,16 @@
}
public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
+ if (zen == ZEN_MODE_OFF) {
+ return false;
+ }
+ // Make an exception to policy for the notification saying that policy has changed
+ if (NotificationManager.Policy.areAllVisualEffectsSuppressed(config.suppressedVisualEffects)
+ && "android".equals(record.sbn.getPackageName())
+ && SystemMessageProto.SystemMessage.NOTE_ZEN_UPGRADE == record.sbn.getId()) {
+ ZenLog.traceNotIntercepted(record, "systemDndChangedNotification");
+ return false;
+ }
switch (zen) {
case Global.ZEN_MODE_NO_INTERRUPTIONS:
// #notevenalarms
@@ -192,9 +215,8 @@
return false;
}
- private static boolean isAlarm(NotificationRecord record) {
+ protected static boolean isAlarm(NotificationRecord record) {
return record.isCategory(Notification.CATEGORY_ALARM)
- || record.isAudioStream(AudioManager.STREAM_ALARM)
|| record.isAudioAttributesUsage(AudioAttributes.USAGE_ALARM);
}
@@ -234,17 +256,8 @@
&& pkg.equals(mDefaultPhoneApp.getPackageName());
}
- @SuppressWarnings("deprecation")
- private boolean isDefaultMessagingApp(NotificationRecord record) {
- final int userId = record.getUserId();
- if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
- final String defaultApp = Secure.getStringForUser(mContext.getContentResolver(),
- Secure.SMS_DEFAULT_APPLICATION, userId);
- return Objects.equals(defaultApp, record.sbn.getPackageName());
- }
-
- private boolean isMessage(NotificationRecord record) {
- return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
+ protected boolean isMessage(NotificationRecord record) {
+ return mMessagingUtil.isMessaging(record.sbn);
}
private static boolean audienceMatches(int source, float contactAffinity) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6ab7748..aa1f7d95 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -602,7 +602,8 @@
pw.println(config);
return;
}
- pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s,"
+ pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
+ + "messages=%b,messagesFrom=%s,"
+ "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
config.allowAlarms, config.allowMedia, config.allowSystem,
config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
@@ -610,6 +611,7 @@
ZenModeConfig.sourceToString(config.allowMessagesFrom),
config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
config.allowWhenScreenOn);
+ pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
final int N = config.automaticRules.size();
@@ -623,7 +625,7 @@
throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser);
if (config != null) {
- if (config.version < ZenModeConfig.XML_VERSION) {
+ if (config.version < ZenModeConfig.XML_VERSION || forRestore) {
Settings.Global.putInt(mContext.getContentResolver(),
Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
}
@@ -782,13 +784,13 @@
}
private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
- Slog.d("beverlyt", "setPreviousRingerMode=" + previousRingerLevel);
Global.putString(
mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
}
- private boolean evaluateZenMode(String reason, boolean setRingerMode) {
+ @VisibleForTesting
+ protected boolean evaluateZenMode(String reason, boolean setRingerMode) {
if (DEBUG) Log.d(TAG, "evaluateZenMode");
final int zenBefore = mZenMode;
final int zen = computeZenMode();
@@ -796,7 +798,7 @@
mZenMode = zen;
setZenModeSetting(mZenMode);
updateRingerModeAffectedStreams();
- if (setRingerMode) {
+ if (setRingerMode && zen != zenBefore) {
applyZenToRingerMode();
}
applyRestrictions();
@@ -813,8 +815,8 @@
}
private int computeZenMode() {
+ if (mConfig == null) return Global.ZEN_MODE_OFF;
synchronized (mConfig) {
- if (mConfig == null) return Global.ZEN_MODE_OFF;
if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
@@ -1018,6 +1020,13 @@
int ringerModeExternalOut = ringerModeNew;
+ if (mZenMode == Global.ZEN_MODE_OFF
+ || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig))) {
+ // in priority only with ringer not muted, save ringer mode changes
+ // in dnd off, save ringer mode changes
+ setPreviousRingerModeSetting(ringerModeNew);
+ }
int newZen = -1;
switch (ringerModeNew) {
case AudioManager.RINGER_MODE_SILENT:
@@ -1046,12 +1055,7 @@
if (newZen != -1) {
setManualZenMode(newZen, null, "ringerModeInternal", null,
false /*setRingerMode*/);
- } else if (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
- && !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig)) {
- // in priority only with ringer not muted, save ringer mode changes
- setPreviousRingerModeSetting(ringerModeNew);
}
-
if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
ringerModeExternal, ringerModeExternalOut);
@@ -1174,8 +1178,7 @@
@VisibleForTesting
protected Notification createZenUpgradeNotification() {
- Intent intent = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS)
- .setPackage("com.android.settings")
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 9bba9ed..24abf86 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -65,6 +65,8 @@
public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
/** Indicates that dexopt should restrict access to private APIs. */
public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
+ /** Indicates that dexopt should convert to CompactDex. */
+ public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 9420a6c..5a7893a 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -266,8 +266,8 @@
throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 7.
- builder.append("7 ");
+ // The current version.
+ builder.append("8 ");
builder.append("dexopt");
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 77bf67d..9e7ad47 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -57,6 +57,7 @@
import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE;
import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB;
import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS;
+import static com.android.server.pm.Installer.DEXOPT_GENERATE_COMPACT_DEX;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -532,12 +533,22 @@
// Some apps are executed with restrictions on hidden API usage. If this app is one
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
+ // Avoid generating CompactDex for modes that are latency critical.
+ final int compilationReason = options.getCompilationReason();
+ boolean generateCompactDex = true;
+ switch (compilationReason) {
+ case PackageManagerService.REASON_FIRST_BOOT:
+ case PackageManagerService.REASON_BOOT:
+ case PackageManagerService.REASON_INSTALL:
+ generateCompactDex = false;
+ }
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
| profileFlag
| (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
| (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0)
+ | (generateCompactDex ? DEXOPT_GENERATE_COMPACT_DEX : 0)
| hiddenApiFlag;
return adjustDexoptFlags(dexFlags);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f12795b..707184f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2592,7 +2592,7 @@
| SCAN_AS_PRIVILEGED,
0);
- // Collected privileged system packages.
+ // Collect privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirTracedLI(privilegedAppDir,
mDefParseFlags
@@ -2611,7 +2611,7 @@
| SCAN_AS_SYSTEM,
0);
- // Collected privileged vendor packages.
+ // Collect privileged vendor packages.
File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
try {
privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
@@ -2642,6 +2642,40 @@
| SCAN_AS_VENDOR,
0);
+ // Collect privileged odm packages. /odm is another vendor partition
+ // other than /vendor.
+ File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
+ "priv-app");
+ try {
+ privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedOdmAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary odm packages. /odm is another vendor partition
+ // other than /vendor.
+ File odmAppDir = new File(Environment.getOdmDirectory(), "app");
+ try {
+ odmAppDir = odmAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(odmAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
+ 0);
+
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirTracedLI(oemAppDir,
@@ -2980,6 +3014,9 @@
}
}
}
+ // Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
+ // SELinux domain.
+ setting.fixSeInfoLocked();
}
// Now that we know all the packages we are keeping,
@@ -3368,6 +3405,13 @@
// "/data/system/package_cache/1"
File cacheDir = FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
+ if (cacheDir == null) {
+ // Something went wrong. Attempt to delete everything and return.
+ Slog.wtf(TAG, "Cache directory cannot be created - wiping base dir " + cacheBaseDir);
+ FileUtils.deleteContentsAndDir(cacheBaseDir);
+ return null;
+ }
+
// The following is a workaround to aid development on non-numbered userdebug
// builds or cases where "adb sync" is used on userdebug builds. If we detect that
// the system partition is newer.
@@ -10376,20 +10420,24 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
- // SELinux sandboxes become more restrictive as targetSdkVersion increases.
- // To ensure that apps with sharedUserId are placed in the same selinux domain
- // without breaking any assumptions about access, put them into the least
- // restrictive targetSdkVersion=25 domain.
- // TODO(b/72290969): Base this on the actual targetSdkVersion(s) of the apps within the
- // sharedUserSetting, instead of defaulting to the least restrictive domain.
- final int targetSdk = (sharedUserSetting != null) ? 25
- : pkg.applicationInfo.targetSdkVersion;
+ // Apps which share a sharedUserId must be placed in the same selinux domain. If this
+ // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its
+ // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be
+ // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the
+ // least restrictive selinux domain.
+ // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion
+ // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This
+ // ensures that all packages continue to run in the same selinux domain.
+ final int targetSdkVersion =
+ ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ?
+ sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion;
// TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync.
// They currently can be if the sharedUser apps are signed with the platform key.
final boolean isPrivileged = (sharedUserSetting != null) ?
sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
- SELinuxMMAC.assignSeInfoValue(pkg, isPrivileged, targetSdk);
+ pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+ pkg.applicationInfo.targetSandboxVersion, targetSdkVersion);
pkg.mExtras = pkgSetting;
pkg.applicationInfo.processName = fixProcessName(
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index a9f1528..b47d966 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -64,6 +64,8 @@
/** Required MAC permissions files */
private static List<File> sMacPermissions = new ArrayList<>();
+ private static final String DEFAULT_SEINFO = "default";
+
// Append privapp to existing seinfo label
private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -307,45 +309,56 @@
}
/**
- * Applies a security label to a package based on an seinfo tag taken from a matched
- * policy. All signature based policy stanzas are consulted and, if no match is
- * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
- * used. The security label is attached to the ApplicationInfo instance of the package
- * in the event that a matching policy was found.
+ * Selects a security label to a package based on input parameters and the seinfo tag taken
+ * from a matched policy. All signature based policy stanzas are consulted and, if no match
+ * is found, the default seinfo label of 'default' is used. The security label is attached to
+ * the ApplicationInfo instance of the package.
*
* @param pkg object representing the package to be labeled.
+ * @param isPrivileged boolean.
+ * @param targetSandboxVersion int.
+ * @param targetSdkVersion int. If this pkg runs as a sharedUser, targetSdkVersion is the
+ * greater of: lowest targetSdk for all pkgs in the sharedUser, or
+ * MINIMUM_TARGETSDKVERSION.
+ * @return String representing the resulting seinfo.
*/
- public static void assignSeInfoValue(PackageParser.Package pkg, boolean isPrivileged,
- int targetSdkVersion) {
+ public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged,
+ int targetSandboxVersion, int targetSdkVersion) {
+ String seInfo = null;
synchronized (sPolicies) {
if (!sPolicyRead) {
if (DEBUG_POLICY) {
Slog.d(TAG, "Policy not read");
}
- return;
- }
- for (Policy policy : sPolicies) {
- String seInfo = policy.getMatchedSeInfo(pkg);
- if (seInfo != null) {
- pkg.applicationInfo.seInfo = seInfo;
- break;
+ } else {
+ for (Policy policy : sPolicies) {
+ seInfo = policy.getMatchedSeInfo(pkg);
+ if (seInfo != null) {
+ break;
+ }
}
}
}
- if (pkg.applicationInfo.targetSandboxVersion == 2)
- pkg.applicationInfo.seInfo += SANDBOX_V2_STR;
-
- if (isPrivileged) {
- pkg.applicationInfo.seInfo += PRIVILEGED_APP_STR;
+ if (seInfo == null) {
+ seInfo = DEFAULT_SEINFO;
}
- pkg.applicationInfo.seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
+ if (targetSandboxVersion == 2) {
+ seInfo += SANDBOX_V2_STR;
+ }
+
+ if (isPrivileged) {
+ seInfo += PRIVILEGED_APP_STR;
+ }
+
+ seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
if (DEBUG_POLICY_INSTALL) {
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
- "seinfo=" + pkg.applicationInfo.seInfo);
+ "seinfo=" + seInfo);
}
+ return seInfo;
}
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2446131..407ceb7 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -39,6 +39,10 @@
int uidFlags;
int uidPrivateFlags;
+ // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
+ // that all apps within the sharedUser run in the same selinux context.
+ int seInfoTargetSdkVersion;
+
final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
final PackageSignatures signatures = new PackageSignatures();
@@ -84,6 +88,11 @@
}
void addPackage(PackageSetting packageSetting) {
+ // If this is the first package added to this shared user, temporarily (until next boot) use
+ // its targetSdkVersion when assigning seInfo for the shared user.
+ if ((packages.size() == 0) && (packageSetting.pkg != null)) {
+ seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
+ }
if (packages.add(packageSetting)) {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
@@ -96,7 +105,7 @@
}
final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
for (PackageSetting ps : packages) {
- if (ps == null) {
+ if ((ps == null) || (ps.pkg == null)) {
continue;
}
pkgList.add(ps.pkg);
@@ -107,4 +116,29 @@
public boolean isPrivileged() {
return (this.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
+
+ /**
+ * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
+ * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
+ * targetSdkVersion of all apps within the shared user, which corresponds to the least
+ * restrictive selinux domain.
+ */
+ public void fixSeInfoLocked() {
+ final List<PackageParser.Package> pkgList = getPackages();
+ if (pkgList == null || pkgList.size() == 0) {
+ return;
+ }
+
+ for (PackageParser.Package pkg : pkgList) {
+ if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
+ seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ }
+ }
+ for (PackageParser.Package pkg : pkgList) {
+ final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
+ pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+ pkg.applicationInfo.targetSandboxVersion, seInfoTargetSdkVersion);
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ab0779b..87be0a2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -427,6 +427,8 @@
KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
}
+ private static final int USER_ACTIVITY_NOTIFICATION_DELAY = 200;
+
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
@@ -674,6 +676,7 @@
private boolean mPendingKeyguardOccluded;
private boolean mKeyguardOccludedChanged;
+ private boolean mNotifyUserActivity;
boolean mShowingDream;
private boolean mLastShowingDream;
@@ -721,6 +724,9 @@
// Behavior of rotation suggestions. (See Settings.Secure.SHOW_ROTATION_SUGGESTION)
int mShowRotationSuggestions;
+ // Whether system navigation keys are enabled
+ boolean mSystemNavigationKeysEnabled;
+
Display mDisplay;
int mLandscapeRotation = 0; // default landscape rotation
@@ -828,6 +834,7 @@
private static final int MSG_LAUNCH_ASSIST = 26;
private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 27;
private static final int MSG_POWER_VERY_LONG_PRESS = 28;
+ private static final int MSG_NOTIFY_USER_ACTIVITY = 29;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -929,6 +936,13 @@
case MSG_HANDLE_ALL_APPS:
launchAllAppsAction();
break;
+ case MSG_NOTIFY_USER_ACTIVITY:
+ removeMessages(MSG_NOTIFY_USER_ACTIVITY);
+ Intent intent = new Intent(ACTION_USER_ACTIVITY_NOTIFICATION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.USER_ACTIVITY);
+ break;
}
}
}
@@ -984,6 +998,9 @@
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POLICY_CONTROL), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
+ UserHandle.USER_ALL);
updateSettings();
}
@@ -2359,6 +2376,9 @@
Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT,
UserHandle.USER_CURRENT);
+ mSystemNavigationKeysEnabled = Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
+ 0, UserHandle.USER_CURRENT) == 1;
// Configure rotation suggestions.
int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
@@ -3860,6 +3880,15 @@
hideRecentApps(true, false);
}
+ // Handle keyboard layout switching.
+ // TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation.
+ if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE
+ && ((metaState & KeyEvent.META_CTRL_MASK) != 0)) {
+ int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+ mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+ return -1;
+ }
+
// Handle input method switching.
if (down && repeatCount == 0
&& (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
@@ -4389,13 +4418,13 @@
@Override
// TODO: Should probably be moved into DisplayFrames.
- public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
+ public boolean getLayoutHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
+ DisplayFrames displayFrames, Rect outFrame, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int pfl = attrs.privateFlags;
- final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
- final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
+ final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
final int displayRotation = displayFrames.mRotation;
final int displayWidth = displayFrames.mDisplayWidth;
final int displayHeight = displayFrames.mDisplayHeight;
@@ -4416,21 +4445,20 @@
}
}
- final boolean layoutInScreenAndInsetDecor =
- (fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
- == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR);
+ final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
+ final boolean layoutInScreenAndInsetDecor = layoutInScreen &&
+ (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
if (layoutInScreenAndInsetDecor && !screenDecor) {
- Rect frame;
int availRight, availBottom;
if (canHideNavigationBar() &&
- (systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
- frame = displayFrames.mUnrestricted;
+ (sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+ outFrame.set(displayFrames.mUnrestricted);
availRight = displayFrames.mUnrestricted.right;
availBottom = displayFrames.mUnrestricted.bottom;
} else {
- frame = displayFrames.mRestricted;
+ outFrame.set(displayFrames.mRestricted);
availRight = displayFrames.mRestricted.right;
availBottom = displayFrames.mRestricted.bottom;
}
@@ -4438,7 +4466,7 @@
availRight - displayFrames.mStable.right,
availBottom - displayFrames.mStable.bottom);
- if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+ if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
if ((fl & FLAG_FULLSCREEN) != 0) {
outContentInsets.set(displayFrames.mStableFullscreen.left,
displayFrames.mStableFullscreen.top,
@@ -4460,14 +4488,25 @@
displayWidth, displayHeight);
calculateRelevantTaskInsets(taskBounds, outStableInsets,
displayWidth, displayHeight);
+ outFrame.intersect(taskBounds);
}
- outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(frame));
+ outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame));
+ return mForceShowSystemBars;
+ } else {
+ if (layoutInScreen) {
+ outFrame.set(displayFrames.mUnrestricted);
+ } else {
+ outFrame.set(displayFrames.mStable);
+ }
+ if (taskBounds != null) {
+ outFrame.intersect(taskBounds);
+ }
+
+ outContentInsets.setEmpty();
+ outStableInsets.setEmpty();
+ outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
return mForceShowSystemBars;
}
- outContentInsets.setEmpty();
- outStableInsets.setEmpty();
- outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
- return mForceShowSystemBars;
}
/**
@@ -5064,11 +5103,12 @@
pf.set(displayFrames.mOverscan);
} else if (canHideNavigationBar()
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
+ && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
+ || type == TYPE_VOLUME_OVERLAY)) {
// Asking for layout as if the nav bar is hidden, lets the application
// extend into the unrestricted overscan screen area. We only do this for
- // application windows to ensure no window that can be above the nav bar can
- // do this.
+ // application windows and certain system windows to ensure no window that
+ // can be above the nav bar can do this.
df.set(displayFrames.mOverscan);
pf.set(displayFrames.mOverscan);
// We need to tell the app about where the frame inside the overscan is, so
@@ -5128,15 +5168,6 @@
if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
"Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
- } else if (type == TYPE_VOLUME_OVERLAY) {
- // Volume overlay covers everything, including the status and navbar
- cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
- "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
- pf.left, pf.top, pf.right, pf.bottom));
} else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
// The navigation bar has Real Ultimate Power.
of.set(displayFrames.mUnrestricted);
@@ -5220,8 +5251,8 @@
"): normal window");
// Otherwise, a normal window must be placed inside the content
// of all screen decorations.
- if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_VOLUME_OVERLAY) {
- // Status bar panels and the volume dialog are the only windows who can go on
+ if (type == TYPE_STATUS_BAR_PANEL) {
+ // Status bar panels can go on
// top of the status bar. They are protected by the STATUS_BAR_SERVICE
// permission, so they have the same privileges as the status bar itself.
cf.set(displayFrames.mRestricted);
@@ -6214,7 +6245,7 @@
if (event.getAction() == KeyEvent.ACTION_UP) {
if (!mAccessibilityManager.isEnabled()
|| !mAccessibilityManager.sendFingerprintGesture(event.getKeyCode())) {
- if (areSystemNavigationKeysEnabled()) {
+ if (mSystemNavigationKeysEnabled) {
sendSystemKeyToStatusBarAsync(event.getKeyCode());
}
}
@@ -7476,6 +7507,13 @@
mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE);
}
+ @Override
+ public void requestUserActivityNotification() {
+ if (!mNotifyUserActivity && !mHandler.hasMessages(MSG_NOTIFY_USER_ACTIVITY)) {
+ mNotifyUserActivity = true;
+ }
+ }
+
/** {@inheritDoc} */
@Override
public void userActivity() {
@@ -7497,6 +7535,12 @@
mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
}
}
+
+ if (mAwake && mNotifyUserActivity) {
+ mHandler.sendEmptyMessageDelayed(MSG_NOTIFY_USER_ACTIVITY,
+ USER_ACTIVITY_NOTIFICATION_DELAY);
+ mNotifyUserActivity = false;
+ }
}
class ScreenLockTimeout implements Runnable {
@@ -7793,11 +7837,6 @@
Settings.Global.THEATER_MODE_ON, 0) == 1;
}
- private boolean areSystemNavigationKeysEnabled() {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
- }
-
@Override
public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
if (!mVibrator.hasVibrator()) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ab331a5..9bd508e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -545,6 +545,12 @@
public int getCameraLensCoverState();
/**
+ * Switch the keyboard layout for the given device.
+ * Direction should be +1 or -1 to go to the next or previous keyboard layout.
+ */
+ public void switchKeyboardLayout(int deviceId, int direction);
+
+ /**
* Switch the input method, to be precise, input method subtype.
*
* @param forwardDirection {@code true} to rotate in a forward direction.
@@ -1145,13 +1151,14 @@
/**
- * Return the insets for the areas covered by system windows. These values are computed on the
+ * Return the layout hints for a newly added window. These values are computed on the
* most recent layout, so they are not guaranteed to be correct.
*
* @param attrs The LayoutParams of the window.
* @param taskBounds The bounds of the task this window is on or {@code null} if no task is
* associated with the window.
* @param displayFrames display frames.
+ * @param outFrame The frame of the window.
* @param outContentInsets The areas covered by system windows, expressed as positive insets.
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
@@ -1160,9 +1167,10 @@
* @return Whether to always consume the navigation bar.
* See {@link #isNavBarForcedShownLw(WindowState)}.
*/
- default boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
+ default boolean getLayoutHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
+ DisplayFrames displayFrames, Rect outFrame, Rect outContentInsets,
+ Rect outStableInsets, Rect outOutsets,
+ DisplayCutout.ParcelableWrapper outDisplayCutout) {
return false;
}
@@ -1716,4 +1724,10 @@
return Integer.toString(mode);
}
}
+
+ /**
+ * Requests that the WindowManager sends WindowManagerPolicy#ACTION_USER_ACTIVITY_NOTIFICATION
+ * on the next user activity.
+ */
+ public void requestUserActivityNotification();
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f77b0ee..055e6ea 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -68,7 +68,6 @@
import android.service.dreams.DreamManagerInternal;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
-import android.util.EventLog;
import android.util.KeyValueListParser;
import android.util.MathUtils;
import android.util.PrintWriterPrinter;
@@ -488,6 +487,9 @@
// The screen brightness to use while dozing.
private int mDozeScreenBrightnessOverrideFromDreamManager = PowerManager.BRIGHTNESS_DEFAULT;
+ // Keep display state when dozing.
+ private boolean mDrawWakeLockOverrideFromSidekick;
+
// Time when we last logged a warning about calling userActivity() without permission.
private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
@@ -1487,7 +1489,7 @@
break;
}
}
- EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
+ EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
// Skip dozing if requested.
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
@@ -1572,7 +1574,7 @@
final long now = SystemClock.uptimeMillis();
final long savedWakeTimeMs = mOverriddenTimeout - now;
if (savedWakeTimeMs >= 0) {
- EventLog.writeEvent(EventLogTags.POWER_SOFT_SLEEP_REQUESTED, savedWakeTimeMs);
+ EventLogTags.writePowerSoftSleepRequested(savedWakeTimeMs);
mOverriddenTimeout = -1;
}
}
@@ -2424,7 +2426,8 @@
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
+ && !mDrawWakeLockOverrideFromSidekick) {
if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
}
@@ -3157,6 +3160,7 @@
synchronized (mLock) {
if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
mUserActivityTimeoutOverrideFromWindowManager = timeoutMillis;
+ EventLogTags.writeUserActivityTimeoutOverride(timeoutMillis);
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
@@ -3176,6 +3180,16 @@
}
}
+ private void setDrawWakeLockOverrideFromSidekickInternal(boolean keepState) {
+ synchronized (mLock) {
+ if (mDrawWakeLockOverrideFromSidekick != keepState) {
+ mDrawWakeLockOverrideFromSidekick = keepState;
+ mDirty |= DIRTY_SETTINGS;
+ updatePowerStateLocked();
+ }
+ }
+ }
+
@VisibleForTesting
void setVrModeEnabled(boolean enabled) {
mIsVrModeEnabled = enabled;
@@ -3381,6 +3395,7 @@
+ mUserInactiveOverrideFromWindowManager);
pw.println(" mDozeScreenStateOverrideFromDreamManager="
+ mDozeScreenStateOverrideFromDreamManager);
+ pw.println(" mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick);
pw.println(" mDozeScreenBrightnessOverrideFromDreamManager="
+ mDozeScreenBrightnessOverrideFromDreamManager);
pw.println(" mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
@@ -3717,6 +3732,10 @@
mDozeScreenStateOverrideFromDreamManager);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto
+ .DRAW_WAKE_LOCK_OVERRIDE_FROM_SIDEKICK,
+ mDrawWakeLockOverrideFromSidekick);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
.DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
mDozeScreenBrightnessOverrideFromDreamManager);
@@ -4703,6 +4722,11 @@
}
@Override
+ public void setDrawWakeLockOverrideFromSidekick(boolean keepState) {
+ setDrawWakeLockOverrideFromSidekickInternal(keepState);
+ }
+
+ @Override
public void setMaximumScreenOffTimeoutFromDeviceAdmin(@UserIdInt int userId, long timeMs) {
setMaximumScreenOffTimeoutFromDeviceAdminInternal(userId, timeMs);
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6e017cd..954627b 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -61,13 +61,19 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.os.KernelCpuSpeedReader;
+import com.android.internal.os.KernelUidCpuTimeReader;
+import com.android.internal.os.KernelUidCpuClusterTimeReader;
+import com.android.internal.os.KernelUidCpuActiveTimeReader;
+import com.android.internal.os.KernelUidCpuFreqTimeReader;
import com.android.internal.os.KernelWakelockReader;
import com.android.internal.os.KernelWakelockStats;
import com.android.internal.os.PowerProfile;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;
@@ -106,7 +112,6 @@
private final ShutdownEventReceiver mShutdownEventReceiver;
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
- private final KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
private IWifiManager mWifiManager = null;
private TelephonyManager mTelephony = null;
private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
@@ -115,6 +120,15 @@
private final StatFs mStatFsTemp =
new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
+ private KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
+ private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
+ private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
+ new KernelUidCpuFreqTimeReader();
+ private KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader =
+ new KernelUidCpuActiveTimeReader();
+ private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
+ new KernelUidCpuClusterTimeReader();
+
public StatsCompanionService(Context context) {
super();
mContext = context;
@@ -159,6 +173,13 @@
numSpeedSteps);
firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
}
+ // use default throttling in
+ // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+ mKernelUidCpuFreqTimeReader.setThrottleInterval(0);
+ long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile);
+ mKernelUidCpuFreqTimeReader.setReadBinary(true);
+ mKernelUidCpuClusterTimeReader.setThrottleInterval(0);
+ mKernelUidCpuActiveTimeReader.setThrottleInterval(0);
}
@Override
@@ -176,6 +197,7 @@
@Override
public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
long subscriptionId, long subscriptionRuleId,
+ String[] cookies,
StatsDimensionsValue dimensionsValue) {
enforceCallingPermission();
IntentSender intentSender = new IntentSender(intentSenderBinder);
@@ -185,10 +207,17 @@
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
.putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
+
+ ArrayList<String> cookieList = new ArrayList<>(cookies.length);
+ for (String cookie : cookies) { cookieList.add(cookie); }
+ intent.putStringArrayListExtra(
+ StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
+
if (DEBUG) {
- Slog.d(TAG, String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s}",
- configUid, configKey, subscriptionId,
- subscriptionRuleId, dimensionsValue));
+ Slog.d(TAG, String.format(
+ "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
+ configUid, configKey, subscriptionId, subscriptionRuleId,
+ Arrays.toString(cookies), dimensionsValue));
}
try {
intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
@@ -258,7 +287,7 @@
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
return; // Keep only replacing or normal add and remove.
}
- Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
+ if (DEBUG) Slog.d(TAG, "StatsCompanionService noticed an app was updated.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd to inform it of an app update");
@@ -676,6 +705,53 @@
}
}
+ private void pullKernelUidCpuTime(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ mKernelUidCpuTimeReader.readAbsolute((uid, userTimeUs, systemTimeUs) -> {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+ e.writeInt(uid);
+ e.writeLong(userTimeUs);
+ e.writeLong(systemTimeUs);
+ pulledData.add(e);
+ });
+ }
+
+ private void pullKernelUidCpuFreqTime(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ mKernelUidCpuFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
+ for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+ e.writeInt(uid);
+ e.writeInt(freqIndex);
+ e.writeLong(cpuFreqTimeMs[freqIndex]);
+ pulledData.add(e);
+ }
+ });
+ }
+
+ private void pullKernelUidCpuClusterTime(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ mKernelUidCpuClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
+ for (int i = 0; i < cpuClusterTimesMs.length; i++) {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+ e.writeInt(uid);
+ e.writeInt(i);
+ e.writeLong(cpuClusterTimesMs[i]);
+ pulledData.add(e);
+ }
+ });
+ }
+
+ private void pullKernelUidCpuActiveTime(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ mKernelUidCpuActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2);
+ e.writeInt(uid);
+ e.writeLong((long)cpuActiveTimesMs);
+ pulledData.add(e);
+ });
+ }
+
private void pullWifiActivityEnergyInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
long token = Binder.clearCallingIdentity();
if (mWifiManager == null) {
@@ -828,6 +904,22 @@
pullCpuTimePerFreq(tagId, ret);
break;
}
+ case StatsLog.CPU_TIME_PER_UID: {
+ pullKernelUidCpuTime(tagId, ret);
+ break;
+ }
+ case StatsLog.CPU_TIME_PER_UID_FREQ: {
+ pullKernelUidCpuFreqTime(tagId, ret);
+ break;
+ }
+ case StatsLog.CPU_CLUSTER_TIME: {
+ pullKernelUidCpuClusterTime(tagId, ret);
+ break;
+ }
+ case StatsLog.CPU_ACTIVE_TIME: {
+ pullKernelUidCpuActiveTime(tagId, ret);
+ break;
+ }
case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: {
pullWifiActivityEnergyInfo(tagId, ret);
break;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index c04522e..2672337 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1728,6 +1728,8 @@
frame.set(win.mContainingFrame);
}
surfaceInsets = win.getAttrs().surfaceInsets;
+ // XXX(b/72757033): These are insets relative to the window frame, but we're really
+ // interested in the insets relative to the frame we chose in the if-blocks above.
insets.set(win.mContentInsets);
stableInsets.set(win.mStableInsets);
}
@@ -2120,4 +2122,12 @@
}
return stringName + ((mIsExiting) ? " mIsExiting=" : "");
}
+
+ Rect getLetterboxInsets() {
+ if (mLetterbox != null) {
+ return mLetterbox.getInsets();
+ } else {
+ return new Rect();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 8fa79ab..0f9735d 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -68,6 +68,17 @@
}
/**
+ * Gets the insets between the outer and inner rects.
+ */
+ public Rect getInsets() {
+ return new Rect(
+ mLeft.getWidth(),
+ mTop.getHeight(),
+ mRight.getWidth(),
+ mBottom.getHeight());
+ }
+
+ /**
* Hides the letterbox.
*
* @param t a transaction in which to hide the letterbox
@@ -141,5 +152,13 @@
mSurface = null;
}
}
+
+ public int getWidth() {
+ return Math.max(0, mLastRight - mLastLeft);
+ }
+
+ public int getHeight() {
+ return Math.max(0, mLastBottom - mLastTop);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index f7344b2..39b886d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,12 +29,12 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
@@ -175,7 +175,7 @@
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- public void initialize() {
+ public void initialize(SparseBooleanArray recentTaskIds) {
// Make leashes for each of the visible tasks and add it to the recents animation to be
// started
final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
@@ -189,7 +189,7 @@
|| config.getActivityType() == ACTIVITY_TYPE_HOME) {
continue;
}
- addAnimation(task);
+ addAnimation(task, !recentTaskIds.get(task.mTaskId));
}
// Skip the animation if there is nothing to animate
@@ -216,11 +216,12 @@
mService.mWindowPlacerLocked.performSurfacePlacement();
}
- private void addAnimation(Task task) {
+ private void addAnimation(Task task, boolean isRecentTaskInvisible) {
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
mService);
- final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
+ final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
+ isRecentTaskInvisible);
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
task.commitPendingTransaction();
mPendingAnimations.add(taskAdapter);
@@ -343,12 +344,14 @@
private class TaskAnimationAdapter implements AnimationAdapter {
- private Task mTask;
+ private final Task mTask;
private SurfaceControl mCapturedLeash;
private OnAnimationFinishedCallback mCapturedFinishCallback;
+ private final boolean mIsRecentTaskInvisible;
- TaskAnimationAdapter(Task task) {
+ TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
mTask = task;
+ mIsRecentTaskInvisible = isRecentTaskInvisible;
}
RemoteAnimationTarget createRemoteAnimationApp() {
@@ -361,7 +364,7 @@
return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
!mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds,
- mTask.getWindowConfiguration());
+ mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
}
@Override
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index ed6e606..169d65e 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -103,6 +103,7 @@
onAnimationFinished();
}
});
+ sendRunningRemoteAnimation(true);
}
private RemoteAnimationTarget[] createAnimations() {
@@ -131,6 +132,7 @@
mService.closeSurfaceTransaction("RemoteAnimationController#finished");
}
}
+ sendRunningRemoteAnimation(false);
}
private void invokeAnimationCancelled() {
@@ -148,6 +150,14 @@
}
}
+ private void sendRunningRemoteAnimation(boolean running) {
+ final int pid = mRemoteAnimationAdapter.getCallingPid();
+ if (pid == 0) {
+ throw new RuntimeException("Calling pid of remote animation was null");
+ }
+ mService.sendSetRunningRemoteAnimation(pid, running);
+ }
+
private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {
RemoteAnimationController mOuter;
@@ -204,7 +214,7 @@
mCapturedLeash, !mAppWindowToken.fillsParent(),
mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
- task.getWindowConfiguration());
+ task.getWindowConfiguration(), false /*isNotInRecents*/);
}
private int getMode() {
@@ -251,6 +261,7 @@
mHandler.removeCallbacks(mTimeoutRunnable);
releaseFinishedCallback();
invokeAnimationCancelled();
+ sendRunningRemoteAnimation(false);
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 94b8518..662d51d 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -193,16 +193,16 @@
int viewVisibility, Rect outContentInsets, Rect outStableInsets,
InputChannel outInputChannel) {
return addToDisplay(window, seq, attrs, viewVisibility, Display.DEFAULT_DISPLAY,
- outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */,
- outInputChannel);
+ new Rect() /* outFrame */, outContentInsets, outStableInsets, null /* outOutsets */,
+ null /* cutout */, outInputChannel);
}
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout,
- InputChannel outInputChannel) {
- return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
+ int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
+ Rect outStableInsets, Rect outOutsets,
+ DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
+ return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
@@ -217,7 +217,8 @@
public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outStableInsets, null /* outOutsets */, null /* cutout */, null);
+ new Rect() /* outFrame */, outContentInsets, outStableInsets, null /* outOutsets */,
+ null /* cutout */, null /* outInputChannel */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 3d7b32c..9310dc4 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -273,7 +273,8 @@
}
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
getInsetsFromTaskBounds(mainWindow, task),
- isLowRamDevice /* reduced */, scaleFraction /* scale */);
+ isLowRamDevice /* reduced */, scaleFraction /* scale */,
+ true /* isRealSnapshot */);
}
private boolean shouldDisableSnapshots() {
@@ -281,17 +282,25 @@
}
private Rect getInsetsFromTaskBounds(WindowState state, Task task) {
- final Rect r = new Rect();
- r.set(state.getContentFrameLw());
- r.intersectUnchecked(state.getStableFrameLw());
+ // XXX(b/72757033): These are insets relative to the window frame, but we're really
+ // interested in the insets relative to the task bounds.
+ Rect insets = minRect(state.mContentInsets, state.mStableInsets);
+ insets = maxRect(insets, state.mAppToken.getLetterboxInsets());
+ return insets;
+ }
- final Rect taskBounds = task.getBounds();
+ private Rect minRect(Rect rect1, Rect rect2) {
+ return new Rect(Math.min(rect1.left, rect2.left),
+ Math.min(rect1.top, rect2.top),
+ Math.min(rect1.right, rect2.right),
+ Math.min(rect1.bottom, rect2.bottom));
+ }
- r.set(Math.max(0, r.left - taskBounds.left),
- Math.max(0, r.top - taskBounds.top),
- Math.max(0, taskBounds.right - r.right),
- Math.max(0, taskBounds.bottom - r.bottom));
- return r;
+ private Rect maxRect(Rect rect1, Rect rect2) {
+ return new Rect(Math.max(rect1.left, rect2.left),
+ Math.max(rect1.top, rect2.top),
+ Math.max(rect1.right, rect2.right),
+ Math.max(rect1.bottom, rect2.bottom));
}
/**
@@ -361,7 +370,8 @@
}
return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(),
topChild.getConfiguration().orientation, mainWindow.mStableInsets,
- ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */);
+ ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */,
+ false /* isRealSnapshot */);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 537f317..31da5f3 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -89,7 +89,8 @@
}
return new TaskSnapshot(buffer, proto.orientation,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
- reducedResolution, reducedResolution ? REDUCED_SCALE : 1f);
+ reducedResolution, reducedResolution ? REDUCED_SCALE : 1f,
+ proto.isRealSnapshot);
} catch (IOException e) {
Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
return null;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 621bee7..086fffa 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -318,6 +318,7 @@
proto.insetTop = mSnapshot.getContentInsets().top;
proto.insetRight = mSnapshot.getContentInsets().right;
proto.insetBottom = mSnapshot.getContentInsets().bottom;
+ proto.isRealSnapshot = mSnapshot.isRealSnapshot();
final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
final File file = getProtoFile(mTaskId, mUserId);
final AtomicFile atomicFile = new AtomicFile(file);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index e4db3b0..a9e53a1 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -198,7 +198,7 @@
}
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
- View.GONE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
+ View.GONE, token.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
tmpRect, tmpCutout, null);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bdd64d5..1ded81d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -181,6 +181,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.TypedValue;
@@ -1104,7 +1105,7 @@
}
public int addWindow(Session session, IWindow client, int seq,
- LayoutParams attrs, int viewVisibility, int displayId,
+ LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
int[] appOp = new int[1];
@@ -1445,8 +1446,8 @@
} else {
taskBounds = null;
}
- if (mPolicy.getInsetHintLw(win.mAttrs, taskBounds, displayFrames, outContentInsets,
- outStableInsets, outOutsets, outDisplayCutout)) {
+ if (mPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, outFrame,
+ outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
}
@@ -2660,11 +2661,12 @@
public void initializeRecentsAnimation(
IRecentsAnimationRunner recentsAnimationRunner,
- RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId) {
+ RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId,
+ SparseBooleanArray recentTaskIds) {
synchronized (mWindowMap) {
mRecentsAnimationController = new RecentsAnimationController(this,
recentsAnimationRunner, callbacks, displayId);
- mRecentsAnimationController.initialize();
+ mRecentsAnimationController.initialize(recentTaskIds);
}
}
@@ -3178,6 +3180,12 @@
// Called by window manager policy. Not exposed externally.
@Override
+ public void switchKeyboardLayout(int deviceId, int direction) {
+ mInputManager.switchKeyboardLayout(deviceId, direction);
+ }
+
+ // Called by window manager policy. Not exposed externally.
+ @Override
public void switchInputMethod(boolean forwardDirection) {
final InputMethodManagerInternal inputMethodManagerInternal =
LocalServices.getService(InputMethodManagerInternal.class);
@@ -4555,6 +4563,7 @@
public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56;
public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57;
public static final int SET_HAS_OVERLAY_UI = 58;
+ public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
/**
* Used to denote that an integer field in a message will not be used.
@@ -4969,6 +4978,10 @@
mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
}
break;
+ case SET_RUNNING_REMOTE_ANIMATION: {
+ mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
@@ -6989,6 +7002,15 @@
mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
}
+ @Override
+ public void requestUserActivityNotification() {
+ if (!checkCallingPermission(android.Manifest.permission.USER_ACTIVITY,
+ "requestUserActivityNotification()")) {
+ throw new SecurityException("Requires USER_ACTIVITY permission");
+ }
+ mPolicy.requestUserActivityNotification();
+ }
+
void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
if (seamlesslyRotated == w.mSeamlesslyRotated) {
return;
@@ -7409,5 +7431,10 @@
SurfaceControl.Builder makeSurfaceBuilder(SurfaceSession s) {
return mSurfaceBuilderFactory.make(s);
}
+
+ void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
+ mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0)
+ .sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2398661..c4185fa 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2284,13 +2284,14 @@
// interactive, the value may persist until the next animation, which could potentially
// be occurring while turning off the screen. This would lead to the screen incorrectly
// turning back on.
- if (hasTurnScreenOnFlag && allowTheaterMode && canTurnScreenOn
- && !mPowerManagerWrapper.isInteractive()) {
- if (DEBUG_VISIBILITY || DEBUG_POWER) {
- Slog.v(TAG, "Relayout window turning screen on: " + this);
+ if (hasTurnScreenOnFlag) {
+ if (allowTheaterMode && canTurnScreenOn && !mPowerManagerWrapper.isInteractive()) {
+ if (DEBUG_VISIBILITY || DEBUG_POWER) {
+ Slog.v(TAG, "Relayout window turning screen on: " + this);
+ }
+ mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
+ "android.server.wm:TURN_ON");
}
- mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
- "android.server.wm:TURN_ON");
if (mAppToken != null) {
mAppToken.setCanTurnScreenOn(false);
@@ -2610,7 +2611,7 @@
setAppOpVisibilityLw(false);
}
} else {
- final int mode = mService.mAppOps.startOpNoThrow(mAppOp, uid, packageName);
+ final int mode = mService.mAppOps.startOpNoThrow(mAppOp, uid, packageName, true);
if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {
setAppOpVisibilityLw(true);
}
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index 14e3578..ecf1a33 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -72,6 +72,7 @@
struct Module {
sp<V1_0::IBroadcastRadio> radioModule;
HalRevision halRev;
+ std::vector<hardware::broadcastradio::V1_0::BandConfig> bands;
};
struct ServiceContext {
@@ -169,7 +170,8 @@
if (module10 == nullptr) continue;
auto idx = ctx.mModules.size();
- ctx.mModules.push_back({module10, halRev});
+ ctx.mModules.push_back({module10, halRev, {}});
+ auto& nModule = ctx.mModules[idx];
ALOGI("loaded broadcast radio module %zu: %s:%s (HAL 1.%d)",
idx, serviceName.c_str(), V1_0::toString(clazz).c_str(), halMinor);
@@ -178,6 +180,7 @@
Return<void> hidlResult;
if (module11 != nullptr) {
hidlResult = module11->getProperties_1_1([&](const V1_1::Properties& properties) {
+ nModule.bands = properties.base.bands;
jModule = convert::ModulePropertiesFromHal(env, properties, idx, serviceName);
});
} else {
@@ -185,6 +188,7 @@
const V1_0::Properties& properties) {
halResult = result;
if (result != Result::OK) return;
+ nModule.bands = properties.bands;
jModule = convert::ModulePropertiesFromHal(env, properties, idx, serviceName);
});
}
@@ -217,7 +221,21 @@
auto module = ctx.mModules[moduleId];
Region region;
- BandConfig bandConfigHal = convert::BandConfigToHal(env, bandConfig, region);
+ BandConfig bandConfigHal;
+ if (bandConfig != nullptr) {
+ bandConfigHal = convert::BandConfigToHal(env, bandConfig, region);
+ } else {
+ region = Region::INVALID;
+ if (module.bands.size() == 0) {
+ ALOGE("No bands defined");
+ return nullptr;
+ }
+ bandConfigHal = module.bands[0];
+ if (bandConfigHal.spacings.size() > 1) {
+ bandConfigHal.spacings = hidl_vec<uint32_t>({ *std::min_element(
+ bandConfigHal.spacings.begin(), bandConfigHal.spacings.end()) });
+ }
+ }
auto tuner = make_javaref(env, env->NewObject(gjni.Tuner.clazz, gjni.Tuner.cstor,
callback, module.halRev, region, withAudio, bandConfigHal.type));
diff --git a/services/core/jni/BroadcastRadio/types.h b/services/core/jni/BroadcastRadio/types.h
index 64a4f63..910bb7c 100644
--- a/services/core/jni/BroadcastRadio/types.h
+++ b/services/core/jni/BroadcastRadio/types.h
@@ -41,6 +41,7 @@
// Keep in sync with REGION_* constants from RadioManager.java.
enum class Region : jint {
+ INVALID = -1,
ITU_1 = 0,
ITU_2 = 1,
OIRT = 2,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 0aaf32c..0967652 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -30,6 +30,7 @@
import android.util.Slog;
import com.android.server.ServiceThread;
+import com.android.server.net.BaseNetdEventCallback;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -50,7 +51,7 @@
private ServiceThread mHandlerThread;
private NetworkLoggingHandler mNetworkLoggingHandler;
- private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+ private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
@Override
public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
long timestamp, int uid) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6259926..165aaac 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -261,6 +261,8 @@
private boolean mOnlyCore;
private boolean mFirstBoot;
private final boolean mRuntimeRestart;
+ private final long mRuntimeStartElapsedTime;
+ private final long mRuntimeStartUptime;
private static final String START_SENSOR_SERVICE = "StartSensorService";
private static final String START_HIDL_SERVICES = "StartHidlServices";
@@ -292,6 +294,9 @@
mFactoryTestMode = FactoryTest.getMode();
// Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
+
+ mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
+ mRuntimeStartUptime = SystemClock.uptimeMillis();
}
private void run() {
@@ -402,7 +407,8 @@
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
- mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
+ mSystemServiceManager.setStartInfo(mRuntimeRestart,
+ mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool.get();
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
index 3d2d8af..bbec7af 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
@@ -60,7 +60,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTransportClientManager = new TransportClientManager(mContext);
+ mTransportClientManager = new TransportClientManager(mContext, new TransportStats());
mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME);
mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
index 5b65473..49ef581f 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -88,6 +88,7 @@
@Mock private TransportConnectionListener mTransportConnectionListener;
@Mock private TransportConnectionListener mTransportConnectionListener2;
@Mock private IBackupTransport.Stub mTransportBinder;
+ private TransportStats mTransportStats;
private TransportClient mTransportClient;
private ComponentName mTransportComponent;
private String mTransportString;
@@ -105,10 +106,12 @@
mTransportComponent =
new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
mTransportString = mTransportComponent.flattenToShortString();
+ mTransportStats = new TransportStats();
mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
mTransportClient =
new TransportClient(
mContext,
+ mTransportStats,
mBindIntent,
mTransportComponent,
"1",
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 356e64b..0ca0a1a 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -15,6 +15,7 @@
frameworks-base-testutils \
services.accessibility \
services.appwidget \
+ services.autofill \
services.backup \
services.core \
services.devicepolicy \
diff --git a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index b62f1ce..5daacd7 100644
--- a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertNotNull;
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.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -729,8 +730,8 @@
private void assertNoCallbacks(Listener l) throws Exception {
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -752,8 +753,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -766,8 +767,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -796,8 +797,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -808,8 +809,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -819,8 +820,8 @@
setAppOps(UID_10_2, PACKAGE_2, false);
verify(l, times(0)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -835,8 +836,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -849,8 +850,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -864,8 +865,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -876,8 +877,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -889,8 +890,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -901,8 +902,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -915,8 +916,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -928,8 +929,8 @@
waitUntilMainHandlerDrain();
// Called once for updating all whitelist and once for updating temp whitelist
verify(l, times(2)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -940,8 +941,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -953,8 +954,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -965,8 +966,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -985,8 +986,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -997,8 +998,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1009,8 +1010,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -1021,8 +1022,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1035,8 +1036,8 @@
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
- verify(l, times(0)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(1)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1047,8 +1048,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -1059,8 +1060,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -1071,8 +1072,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
@@ -1083,8 +1084,8 @@
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
- verify(l, times(1)).updateJobsForUid(eq(UID_10_1));
- verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+ verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 32a29a2..bda68d1 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -26,6 +26,8 @@
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static org.junit.Assert.assertEquals;
@@ -99,7 +101,7 @@
// Simulate the a resumed activity set during
// {@link ActivityStack#resumeTopActivityUncheckedLocked}.
mSupervisor.inResumeTopActivity = true;
- mStack.mResumedActivity = r;
+ r.setState(RESUMED, "testNoPauseDuringResumeTopActivity");
final boolean waiting = mStack.goToSleepIfPossible(false);
@@ -107,7 +109,18 @@
assertFalse(waiting);
// Make sure the resumed activity is untouched.
- assertEquals(mStack.mResumedActivity, r);
+ assertEquals(mStack.getResumedActivity(), r);
+ }
+
+ @Test
+ public void testResumedActivity() throws Exception {
+ final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+ assertEquals(mStack.getResumedActivity(), null);
+ r.setState(RESUMED, "testResumedActivity");
+ assertEquals(mStack.getResumedActivity(), r);
+ r.setState(PAUSING, "testResumedActivity");
+ assertEquals(mStack.getResumedActivity(), null);
+
}
@Test
@@ -486,4 +499,45 @@
verify(lifecycleManager, times(1)).scheduleTransaction(eq(app.thread),
eq(r.appToken), any(DestroyActivityItem.class));
}
+
+ @Test
+ public void testFinishDisabledPackageActivities() throws Exception {
+ final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+
+ // Making the second activity a task overlay without an app means it will be removed from
+ // the task's activities as well once first activity is removed.
+ secondActivity.mTaskOverlay = true;
+ secondActivity.app = null;
+
+ assertEquals(mTask.mActivities.size(), 2);
+
+ mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName, null,
+ true /* doit */, true /* evenPersistent */, UserHandle.USER_ALL);
+
+ assertTrue(mTask.mActivities.isEmpty());
+ assertTrue(mStack.getAllTasks().isEmpty());
+ }
+
+ @Test
+ public void testHandleAppDied() throws Exception {
+ final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
+
+ // Making the first activity a task overlay means it will be removed from the task's
+ // activities as well once second activity is removed as handleAppDied processes the
+ // activity list in reverse.
+ firstActivity.mTaskOverlay = true;
+ firstActivity.app = null;
+
+ // second activity will be immediately removed as it has no state.
+ secondActivity.haveState = false;
+
+ assertEquals(mTask.mActivities.size(), 2);
+
+ mStack.handleAppDiedLocked(secondActivity.app);
+
+ assertTrue(mTask.mActivities.isEmpty());
+ assertTrue(mStack.getAllTasks().isEmpty());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index b58c700..5906db3 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -30,6 +30,7 @@
import android.app.IApplicationThread;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.WindowLayout;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.graphics.Rect;
@@ -39,6 +40,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.view.Gravity;
import org.junit.runner.RunWith;
import org.junit.Test;
@@ -52,6 +54,7 @@
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -64,6 +67,8 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.am.ActivityStarter.Factory;
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
+import com.android.server.am.TaskRecord.TaskRecordFactory;
/**
* Tests for the {@link ActivityStarter} class.
@@ -197,11 +202,6 @@
final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
? null : new ActivityInfo();
- if (aInfo != null) {
- aInfo.applicationInfo = new ApplicationInfo();
- aInfo.applicationInfo.packageName = ActivityBuilder.DEFAULT_PACKAGE;
- }
-
IVoiceInteractionSession voiceSession =
containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
? mock(IVoiceInteractionSession.class) : null;
@@ -210,6 +210,12 @@
final ActivityBuilder builder = new ActivityBuilder(service).setTask(
new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
+ if (aInfo != null) {
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.packageName =
+ ActivityBuilder.getDefaultComponent().getPackageName();
+ }
+
// Offset uid by one from {@link ActivityInfo} to simulate different uids.
if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
builder.setUid(aInfo.applicationInfo.uid + 1);
@@ -284,9 +290,85 @@
}
}
-// TODO(b/69270257): Add test to verify task layout is passed additional data such as activity and
-// source.
-// @Test
-// public void testCreateTaskLayout() {
-// }
+ private ActivityStarter prepareStarter() {
+ // always allow test to start activity.
+ doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission(
+ any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
+ anyBoolean(), any(), any(), any());
+
+ // instrument the stack and task used.
+ final ActivityStack stack = spy(mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */));
+ final TaskRecord task =
+ spy(new TaskBuilder(mService.mStackSupervisor).setStack(stack).build());
+
+ // supervisor needs a focused stack.
+ mService.mStackSupervisor.mFocusedStack = task.getStack();
+
+ // use factory that only returns spy task.
+ final TaskRecordFactory factory = mock(TaskRecordFactory.class);
+ TaskRecord.setTaskRecordFactory(factory);
+
+ // return task when created.
+ doReturn(task).when(factory).create(any(), anyInt(), any(), any(), any(), any());
+
+ // direct starter to use spy stack.
+ doReturn(stack).when(mService.mStackSupervisor)
+ .getLaunchStack(any(), any(), any(), anyBoolean());
+ doReturn(stack).when(mService.mStackSupervisor)
+ .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
+
+ // ignore the start request.
+ doNothing().when(stack)
+ .startActivityLocked(any(), any(), anyBoolean(), anyBoolean(), any());
+
+ // ignore requests to create window container.
+ doNothing().when(task).createWindowContainer(anyBoolean(), anyBoolean());
+
+ return new ActivityStarter(mController, mService,
+ mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
+ }
+
+ /**
+ * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
+ * when we are laying out a new task.
+ */
+ @Test
+ public void testCreateTaskLayout() {
+ // modifier for validating passed values.
+ final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
+ mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
+
+ // add custom values to activity info to make unique.
+ final ActivityInfo info = new ActivityInfo();
+ final Rect launchBounds = new Rect(0, 0, 20, 30);
+ final Intent intent = new Intent();
+
+ intent.setComponent(ActivityBuilder.getDefaultComponent());
+
+ final WindowLayout windowLayout =
+ new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
+
+ info.windowLayout = windowLayout;
+ info.applicationInfo = new ApplicationInfo();
+ info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
+
+ // create starter.
+ final ActivityStarter optionStarter = prepareStarter();
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(launchBounds);
+
+ // run starter.
+ optionStarter
+ .setIntent(intent)
+ .setReason("testCreateTaskLayout")
+ .setActivityInfo(info)
+ .setActivityOptions(new SafeActivityOptions(options))
+ .execute();
+
+ // verify that values are passed to the modifier.
+ verify(modifier, times(1)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
+ any(), any());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index ff7b1d0..3041a5f 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -67,6 +67,12 @@
private final Context mContext = InstrumentationRegistry.getContext();
private HandlerThread mHandlerThread;
+ // Default package name
+ static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
+
+ // Default base activity name
+ private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
+
@Before
public void setUp() throws Exception {
if (!sOneTimeSetupDone) {
@@ -95,6 +101,7 @@
protected ActivityManagerService setupActivityManagerService(ActivityManagerService service) {
service = spy(service);
doReturn(mock(IPackageManager.class)).when(service).getPackageManager();
+ doNothing().when(service).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt());
service.mWindowManager = prepareMockWindowManager();
return service;
}
@@ -106,11 +113,7 @@
// An id appended to the end of the component name to make it unique
private static int sCurrentActivityId = 0;
- // Default package name
- static final String DEFAULT_PACKAGE = "com.foo";
- // Default base activity name
- private static final String DEFAULT_BASE_ACTIVITY_NAME = ".BarActivity";
private final ActivityManagerService mService;
@@ -129,6 +132,11 @@
return this;
}
+ static ComponentName getDefaultComponent() {
+ return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_PACKAGE_NAME);
+ }
+
ActivityBuilder setTask(TaskRecord task) {
mTaskRecord = task;
return this;
@@ -152,8 +160,8 @@
ActivityRecord build() {
if (mComponent == null) {
final int id = sCurrentActivityId++;
- mComponent = ComponentName.createRelative(DEFAULT_PACKAGE,
- DEFAULT_BASE_ACTIVITY_NAME + id);
+ mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_CLASS_NAME + id);
}
if (mCreateTask) {
@@ -191,6 +199,9 @@
* Builder for creating new tasks.
*/
protected static class TaskBuilder {
+ // Default package name
+ static final String DEFAULT_PACKAGE = "com.bar";
+
private final ActivityStackSupervisor mSupervisor;
private ComponentName mComponent;
@@ -252,6 +263,11 @@
aInfo.applicationInfo.packageName = mPackage;
Intent intent = new Intent();
+ if (mComponent == null) {
+ mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_CLASS_NAME);
+ }
+
intent.setComponent(mComponent);
intent.setFlags(mFlags);
@@ -312,6 +328,8 @@
doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean());
// Do not schedule idle timeouts
doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
+ // unit test version does not handle launch wake lock
+ doNothing().when(supervisor).acquireLaunchWakelock();
supervisor.initialize();
@@ -355,7 +373,8 @@
// Just return the current front task. This is called internally so we cannot use spy to mock this out.
@Override
- ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+ ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus,
+ boolean ignoreCurrent) {
return mFocusedStack;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
new file mode 100644
index 0000000..d5a28f6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 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.autofill;
+
+import static com.android.server.autofill.AutofillManagerService.getWhitelistedCompatModePackages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class AutofillManagerServiceTest {
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_null() {
+ assertThat(getWhitelistedCompatModePackages(null)).isNull();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_empty() {
+ assertThat(getWhitelistedCompatModePackages("")).isNull();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
+ assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+ .containsExactly("one_is_the_loniest_package", null);
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageMissingEndDelimiter() {
+ assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageOneUrl() {
+ final Map<String, String[]> result =
+ getWhitelistedCompatModePackages("one_is_the_loniest_package[url]");
+ assertThat(result).hasSize(1);
+ assertThat(result.get("one_is_the_loniest_package")).asList().containsExactly("url");
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageMultipleUrls() {
+ final Map<String, String[]> result =
+ getWhitelistedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
+ assertThat(result).hasSize(1);
+ assertThat(result.get("one_is_the_loniest_package")).asList()
+ .containsExactly("4", "5", "8", "15", "16", "23", "42");
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
+ final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
+ assertThat(result).hasSize(1);
+ assertThat(result.get("one")).isNull();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_multiplePackagesMultipleUrls() {
+ final Map<String, String[]> result =
+ getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
+ assertThat(result).hasSize(3);
+ assertThat(result.get("p1")).asList().containsExactly("p1u1");
+ assertThat(result.get("p2")).isNull();
+ assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_threePackagesOneInvalid() {
+ final Map<String, String[]> result =
+ getWhitelistedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
+ assertThat(result).hasSize(2);
+ assertThat(result.get("p1")).asList().containsExactly("p1u1");
+ assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index 091d9bd..f740654 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -42,7 +42,11 @@
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
+import java.time.Instant;
import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -257,7 +261,7 @@
@Test
public void testInstallationOptionWithoutFreeze() {
// Also duplicated at com.google.android.gts.deviceowner.SystemUpdatePolicyTest
- final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800);
+ final long millis_2018_01_01 = toMillis(2018, 1, 1);
SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy();
assertInstallationOption(SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, Long.MAX_VALUE,
@@ -294,11 +298,11 @@
@Test
public void testInstallationOptionWithFreeze() throws Exception {
- final long millis_2016_02_29 = TimeUnit.SECONDS.toMillis(1456704000);
- final long millis_2017_01_31 = TimeUnit.SECONDS.toMillis(1485820800);
- final long millis_2017_02_28 = TimeUnit.SECONDS.toMillis(1488240000);
- final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800);
- final long millis_2018_08_01 = TimeUnit.SECONDS.toMillis(1533081600);
+ final long millis_2016_02_29 = toMillis(2016, 2, 29);
+ final long millis_2017_01_31 = toMillis(2017, 1, 31);
+ final long millis_2017_02_28 = toMillis(2017, 2, 28);
+ final long millis_2018_01_01 = toMillis(2018, 1, 1);
+ final long millis_2018_08_01 = toMillis(2018, 8, 1);
SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy();
setFreezePeriods(p, "01-01", "01-31");
@@ -313,12 +317,12 @@
// Freeze period contains leap day Feb 29
p = SystemUpdatePolicy.createPostponeInstallPolicy();
- setFreezePeriods(p, "02-01", "03-15");
- // Freezed until 3/31, note 2016 is a leap year
- assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ setFreezePeriods(p, "02-01", "03-05");
+ // Freezed until 3/5, note 2016 is a leap year
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6),
millis_2016_02_29, p);
- // Freezed until 3/31, note 2017 is not a leap year
- assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ // Freezed until 3/5, note 2017 is not a leap year
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6),
millis_2017_02_28, p);
// Next freeze is 2018/2/1
assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, TimeUnit.DAYS.toMillis(31),
@@ -333,12 +337,12 @@
assertInstallationOption(
SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1),
millis_2017_02_28, p);
- setFreezePeriods(p, "02-28", "03-15");
+ setFreezePeriods(p, "02-28", "03-05");
assertInstallationOption(
- SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6),
millis_2016_02_29, p);
assertInstallationOption(
- SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(6),
millis_2017_02_28, p);
// Freeze period end on or right after leap day
@@ -382,10 +386,10 @@
// Two freeze periods
p = SystemUpdatePolicy.createAutomaticInstallPolicy();
- setFreezePeriods(p, "05-01", "06-01", "12-01", "01-31");
- // automatic policy for August, September, November and December
+ setFreezePeriods(p, "05-01", "06-01", "11-01", "01-29");
+ // automatic policy for July, August, September and October
assertInstallationOption(
- SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(122),
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(92),
millis_2018_08_01, p);
}
@@ -510,4 +514,9 @@
return result;
}
}
+
+ private long toMillis(int year, int month, int day) {
+ return LocalDateTime.of(year, month, day, 0, 0, 0).atZone(ZoneId.systemDefault())
+ .toInstant().toEpochMilli();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index e864870..96f8160 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -43,6 +43,7 @@
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.server.LocalServices;
import org.mockito.invocation.InvocationOnMock;
@@ -67,6 +68,7 @@
private ArrayList<UserInfo> mPrimaryUserProfiles = new ArrayList<>();
LockSettingsService mService;
+ LockSettingsInternal mLocalService;
MockLockSettingsContext mContext;
LockSettingsStorageTestable mStorage;
@@ -95,6 +97,7 @@
mDevicePolicyManager = mock(DevicePolicyManager.class);
mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class);
+ LocalServices.removeServiceForTest(LockSettingsInternal.class);
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
@@ -146,6 +149,7 @@
// Adding a fake Device Owner app which will enable escrow token support in LSS.
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
+ mLocalService = LocalServices.getService(LockSettingsInternal.class);
}
private UserInfo installChildProfile(int profileId) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 294c3e9..e9f9800 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -300,14 +300,14 @@
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
PRIMARY_USER_ID).getResponseCode();
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
// Verify DPM gets notified about new device lock
@@ -329,16 +329,16 @@
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, handle,
- TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
- mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
@@ -355,18 +355,19 @@
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
- mService.setLockCredentialWithToken(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(NEWPASSWORD,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(),
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
@@ -378,8 +379,8 @@
throws RemoteException {
final String TOKEN = "some-high-entropy-secure-token";
enableSyntheticPassword();
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
}
@@ -388,8 +389,8 @@
throws RemoteException {
final String TOKEN = "some-high-entropy-secure-token";
initializeCredentialUnderSP(null, PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
}
@@ -404,15 +405,15 @@
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
enableSyntheticPassword();
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
// Token not activated immediately since user password exists
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
// Activate token (password gets migrated to SP at the same time)
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Verify token is activated
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
public void testPasswordData_serializeDeserialize() {
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
index c6800be..b6be3a4 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -31,6 +31,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@@ -278,22 +279,70 @@
}
@Test
- public void insetHint_screenDecorWindow() {
+ public void layoutHint_screenDecorWindow() {
addDisplayCutout();
mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ final Rect frame = new Rect();
final Rect content = new Rect();
final Rect stable = new Rect();
final Rect outsets = new Rect();
final DisplayCutout.ParcelableWrapper cutout = new DisplayCutout.ParcelableWrapper();
- mPolicy.getInsetHintLw(mAppWindow.attrs, null /* taskBounds */, mFrames, content,
+ mPolicy.getLayoutHintLw(mAppWindow.attrs, null /* taskBounds */, mFrames, frame, content,
stable, outsets, cutout);
+ assertThat(frame, equalTo(mFrames.mUnrestricted));
assertThat(content, equalTo(new Rect()));
assertThat(stable, equalTo(new Rect()));
assertThat(outsets, equalTo(new Rect()));
assertThat(cutout.get(), equalTo(DisplayCutout.NO_CUTOUT));
}
+
+ @Test
+ public void layoutHint_appWindow() {
+ // Initialize DisplayFrames
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+
+ final Rect outFrame = new Rect();
+ final Rect outContentInsets = new Rect();
+ final Rect outStableInsets = new Rect();
+ final Rect outOutsets = new Rect();
+ final DisplayCutout.ParcelableWrapper outDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+
+ mPolicy.getLayoutHintLw(mAppWindow.attrs, null, mFrames, outFrame, outContentInsets,
+ outStableInsets, outOutsets, outDisplayCutout);
+
+ assertThat(outFrame, is(mFrames.mUnrestricted));
+ assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
+ assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
+ assertThat(outOutsets, is(new Rect()));
+ assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
+ }
+
+ @Test
+ public void layoutHint_appWindowInTask() {
+ // Initialize DisplayFrames
+ mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+
+ final Rect taskBounds = new Rect(100, 100, 200, 200);
+
+ final Rect outFrame = new Rect();
+ final Rect outContentInsets = new Rect();
+ final Rect outStableInsets = new Rect();
+ final Rect outOutsets = new Rect();
+ final DisplayCutout.ParcelableWrapper outDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+
+ mPolicy.getLayoutHintLw(mAppWindow.attrs, taskBounds, mFrames, outFrame, outContentInsets,
+ outStableInsets, outOutsets, outDisplayCutout);
+
+ assertThat(outFrame, is(taskBounds));
+ assertThat(outContentInsets, is(new Rect()));
+ assertThat(outStableInsets, is(new Rect()));
+ assertThat(outOutsets, is(new Rect()));
+ assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
+ }
}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 759894b..8d5214a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -61,7 +61,7 @@
mStack = createTaskStackOnDisplay(mDisplayContent);
mTask = createTaskInStack(mStack, 0 /* userId */);
- mToken = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
mTask.addChild(mToken, 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index a8556bd..064e077 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -33,7 +33,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import org.junit.Ignore;
+import android.support.test.filters.FlakyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -193,7 +193,8 @@
assertEquals(dc, stack.getDisplayContent());
final Task task = createTaskInStack(stack, 0 /* userId */);
- final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
+ final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
+ dc);
task.addChild(token, 0);
assertEquals(dc, task.getDisplayContent());
assertEquals(dc, token.getDisplayContent());
@@ -265,14 +266,14 @@
final TaskStack stack0 = createTaskStackOnDisplay(dc0);
final Task task0 = createTaskInStack(stack0, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken token =
- new WindowTestUtils.TestAppWindowToken(dc0);
+ WindowTestUtils.createTestAppWindowToken(dc0);
task0.addChild(token, 0);
dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
sWm.registerPointerEventListener(dc0.mTapDetector);
final TaskStack stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken token1 =
- new WindowTestUtils.TestAppWindowToken(dc0);
+ WindowTestUtils.createTestAppWindowToken(dc0);
task1.addChild(token1, 0);
dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
sWm.registerPointerEventListener(dc1.mTapDetector);
@@ -299,7 +300,7 @@
}
@Test
- @Ignore
+ @FlakyTest(bugId = 37908381)
public void testFocusedWindowMultipleDisplays() throws Exception {
// Create a focusable window and check that focus is calculated correctly
final WindowState window1 =
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 57da6a3..a09656c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -89,7 +89,7 @@
* Creates a window state which can be used as a drop target.
*/
private WindowState createDropTargetWindow(String name, int ownerId) {
- final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(
+ final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
mDisplayContent);
final TaskStack stack = createStackControllerOnStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 96fbc14..80cbf2a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -42,7 +42,7 @@
/**
* Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
*
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotPersisterLoaderTest
+ * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
*/
@MediumTest
@Presubmit
@@ -163,6 +163,23 @@
}
@Test
+ public void testIsRealSnapshotPersistAndLoadSnapshot() {
+ TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */);
+ TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */);
+ assertTrue(a.isRealSnapshot());
+ assertFalse(b.isRealSnapshot());
+ mPersister.persistSnapshot(1, mTestUserId, a);
+ mPersister.persistSnapshot(2, mTestUserId, b);
+ mPersister.waitForQueueEmpty();
+ final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
+ final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
+ assertNotNull(snapshotA);
+ assertNotNull(snapshotB);
+ assertTrue(snapshotA.isRealSnapshot());
+ assertFalse(snapshotB.isRealSnapshot());
+ }
+
+ @Test
public void testRemoveObsoleteFiles() {
mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index b49a0fd..2ad5bf4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -84,12 +84,16 @@
}
TaskSnapshot createSnapshot(float scale) {
+ return createSnapshot(scale, true /* isRealSnapshot */);
+ }
+
+ TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot) {
final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS,
- scale < 1f /* reducedResolution */, scale);
+ scale < 1f /* reducedResolution */, scale, isRealSnapshot);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 4288eac..d5334ba 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -60,7 +60,7 @@
final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
final TaskSnapshot snapshot = new TaskSnapshot(buffer,
- ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
+ ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */);
mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
ORIENTATION_PORTRAIT);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 71bcae7..ca1994f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -54,8 +54,8 @@
// Stack should contain visible app window to be considered visible.
final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
assertFalse(mPinnedStack.isVisible());
- final WindowTestUtils.TestAppWindowToken pinnedApp = new WindowTestUtils.TestAppWindowToken(
- mDisplayContent);
+ final WindowTestUtils.TestAppWindowToken pinnedApp =
+ WindowTestUtils.createTestAppWindowToken(mDisplayContent);
pinnedTask.addChild(pinnedApp, 0 /* addPos */);
assertTrue(mPinnedStack.isVisible());
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index 0ef78f4..eaf71f0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -65,13 +65,13 @@
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
WindowTestUtils.TestAppWindowToken appWindowToken1 =
- new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ WindowTestUtils.createTestAppWindowToken(mDisplayContent);
task1.addChild(appWindowToken1, 0);
appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
WindowTestUtils.TestAppWindowToken appWindowToken2 =
- new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ WindowTestUtils.createTestAppWindowToken(mDisplayContent);
task2.addChild(appWindowToken2, 0);
appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
@@ -85,13 +85,13 @@
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
WindowTestUtils.TestAppWindowToken appWindowToken1 =
- new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ WindowTestUtils.createTestAppWindowToken(mDisplayContent);
task1.addChild(appWindowToken1, 0);
appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
WindowTestUtils.TestAppWindowToken appWindowToken2 =
- new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ WindowTestUtils.createTestAppWindowToken(mDisplayContent);
task2.addChild(appWindowToken2, 0);
appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 34c5db3..6784e30 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -652,4 +652,8 @@
@Override
public void onScreenMagnificationStateChanged(boolean active) {
}
+
+ @Override
+ public void requestUserActivityNotification() {
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 4a22a29..a5c47de 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -44,7 +44,7 @@
@Test
public void testFlow() throws Exception {
- final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token);
sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
sWm.mUnknownAppVisibilityController.notifyRelayouted(token);
@@ -56,8 +56,8 @@
@Test
public void testMultiple() throws Exception {
- final AppWindowToken token1 = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
- final AppWindowToken token2 = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ final AppWindowToken token1 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+ final AppWindowToken token2 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token1);
sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
sWm.mUnknownAppVisibilityController.notifyLaunched(token2);
@@ -72,7 +72,7 @@
@Test
public void testClear() throws Exception {
- final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token);
sWm.mUnknownAppVisibilityController.clear();;
assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
@@ -80,7 +80,7 @@
@Test
public void testAppRemoved() throws Exception {
- final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token);
sWm.mUnknownAppVisibilityController.appRemovedOrHidden(token);
assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 7d6301cc..b5d5fc6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -114,7 +114,8 @@
// Just any non zero value.
sWm.mSystemDecorLayer = 10000;
- mWindowToken = new WindowTestUtils.TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
+ mWindowToken = WindowTestUtils.createTestAppWindowToken(
+ sWm.getDefaultDisplayContentLocked());
mStubStack = new TaskStack(sWm, 0, null);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 678aa64..cdcb949 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -260,7 +260,7 @@
// Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an
// appWindowToken. Both windows have the FLAG_TURNS_SCREEN_ON so both should call wakeup
- final WindowToken windowToken = new WindowTestUtils.TestWindowToken(FIRST_SUB_WINDOW,
+ final WindowToken windowToken = WindowTestUtils.createTestWindowToken(FIRST_SUB_WINDOW,
mDisplayContent);
final WindowState firstWindow = createWindow(null, TYPE_APPLICATION, windowToken,
"firstWindow");
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 012fc23..f4cdc90 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -87,10 +87,12 @@
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
int userId) {
- final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
- new ActivityManager.TaskDescription(), null);
- stack.addTask(newTask, POSITION_TOP);
- return newTask;
+ synchronized (service.mWindowMap) {
+ final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
+ new ActivityManager.TaskDescription(), null);
+ stack.addTask(newTask, POSITION_TOP);
+ return newTask;
+ }
}
/**
@@ -108,11 +110,17 @@
}
}
+ static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
+ synchronized (dc.mService.mWindowMap) {
+ return new TestAppWindowToken(dc);
+ }
+ }
+
/** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
public static class TestAppWindowToken extends AppWindowToken {
boolean mOnTop = false;
- TestAppWindowToken(DisplayContent dc) {
+ private TestAppWindowToken(DisplayContent dc) {
super(dc.mService, new IApplicationToken.Stub() {
public String getName() {return null;}
}, false, dc, true /* fillsParent */);
@@ -158,14 +166,21 @@
}
}
+ static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
+ return createTestWindowToken(type, dc, false /* persistOnEmpty */);
+ }
+
+ static TestWindowToken createTestWindowToken(int type, DisplayContent dc,
+ boolean persistOnEmpty) {
+ synchronized (dc.mService.mWindowMap) {
+ return new TestWindowToken(type, dc, persistOnEmpty);
+ }
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
public static class TestWindowToken extends WindowToken {
- TestWindowToken(int type, DisplayContent dc) {
- this(type, dc, false /* persistOnEmpty */);
- }
-
- TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
+ private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
super(dc.mService, mock(IBinder.class), type, persistOnEmpty, dc,
false /* ownerCanManageAppTokens */);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 7499190..6fa2740 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -61,6 +61,8 @@
/**
* Common base class for window manager unit test classes.
+ *
+ * Make sure any requests to WM hold the WM lock if needed b/73966377
*/
class WindowTestsBase {
private static final String TAG = WindowTestsBase.class.getSimpleName();
@@ -120,21 +122,24 @@
// Set-up some common windows.
mCommonWindows = new HashSet();
- mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
- mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
- sWm.mInputMethodWindow = mImeWindow;
- mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
- "mImeDialogWindow");
- mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
- mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
- mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
- "mDockedDividerWindow");
- mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
- mChildAppWindowAbove = createCommonWindow(mAppWindow, TYPE_APPLICATION_ATTACHED_DIALOG,
- "mChildAppWindowAbove");
- mChildAppWindowBelow = createCommonWindow(mAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
- "mChildAppWindowBelow");
-
+ synchronized (sWm.mWindowMap) {
+ mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
+ mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
+ sWm.mInputMethodWindow = mImeWindow;
+ mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
+ "mImeDialogWindow");
+ mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
+ mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
+ mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
+ "mDockedDividerWindow");
+ mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
+ mChildAppWindowAbove = createCommonWindow(mAppWindow,
+ TYPE_APPLICATION_ATTACHED_DIALOG,
+ "mChildAppWindowAbove");
+ mChildAppWindowBelow = createCommonWindow(mAppWindow,
+ TYPE_APPLICATION_MEDIA_OVERLAY,
+ "mChildAppWindowBelow");
+ }
// Adding a display will cause freezing the display. Make sure to wait until it's
// unfrozen to not run into race conditions with the tests.
waitUntilHandlersIdle();
@@ -187,11 +192,13 @@
}
private WindowState createCommonWindow(WindowState parent, int type, String name) {
- final WindowState win = createWindow(parent, type, name);
- mCommonWindows.add(win);
- // Prevent common windows from been IMe targets
- win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
- return win;
+ synchronized (sWm.mWindowMap) {
+ final WindowState win = createWindow(parent, type, name);
+ mCommonWindows.add(win);
+ // Prevent common windows from been IMe targets
+ win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+ return win;
+ }
}
/** Asserts that the first entry is greater than the second entry. */
@@ -215,11 +222,13 @@
private WindowToken createWindowToken(
DisplayContent dc, int windowingMode, int activityType, int type) {
- if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
- return new WindowTestUtils.TestWindowToken(type, dc);
- }
+ synchronized (sWm.mWindowMap) {
+ if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
+ return WindowTestUtils.createTestWindowToken(type, dc);
+ }
- return createAppWindowToken(dc, windowingMode, activityType);
+ return createAppWindowToken(dc, windowingMode, activityType);
+ }
}
AppWindowToken createAppWindowToken(DisplayContent dc, int windowingMode, int activityType) {
@@ -227,81 +236,103 @@
dc).mContainer;
final Task task = createTaskInStack(stack, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken appWindowToken =
- new WindowTestUtils.TestAppWindowToken(mDisplayContent);
+ WindowTestUtils.createTestAppWindowToken(dc);
task.addChild(appWindowToken, 0);
return appWindowToken;
}
WindowState createWindow(WindowState parent, int type, String name) {
- return (parent == null)
- ? createWindow(parent, type, mDisplayContent, name)
- : createWindow(parent, type, parent.mToken, name);
+ synchronized (sWm.mWindowMap) {
+ return (parent == null)
+ ? createWindow(parent, type, mDisplayContent, name)
+ : createWindow(parent, type, parent.mToken, name);
+ }
}
WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
int type, DisplayContent dc, String name) {
- final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
- return createWindow(parent, type, token, name);
+ synchronized (sWm.mWindowMap) {
+ final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
+ return createWindow(parent, type, token, name);
+ }
}
WindowState createAppWindow(Task task, int type, String name) {
- final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
- task.addChild(token, 0);
- return createWindow(null, type, token, name);
+ synchronized (sWm.mWindowMap) {
+ final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+ task.addChild(token, 0);
+ return createWindow(null, type, token, name);
+ }
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name);
+ synchronized (sWm.mWindowMap) {
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+ return createWindow(parent, type, token, name);
+ }
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
boolean ownerCanAddInternalSystemWindow) {
- final WindowToken token = createWindowToken(
- dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
- return createWindow(parent, type, token, name, 0 /* ownerId */,
- ownerCanAddInternalSystemWindow);
+ synchronized (sWm.mWindowMap) {
+ final WindowToken token = createWindowToken(
+ dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+ return createWindow(parent, type, token, name, 0 /* ownerId */,
+ ownerCanAddInternalSystemWindow);
+ }
}
static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
- return createWindow(parent, type, token, name, 0 /* ownerId */,
- false /* ownerCanAddInternalSystemWindow */);
+ synchronized (sWm.mWindowMap) {
+ return createWindow(parent, type, token, name, 0 /* ownerId */,
+ false /* ownerCanAddInternalSystemWindow */);
+ }
}
static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId, boolean ownerCanAddInternalSystemWindow) {
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
- attrs.setTitle(name);
+ synchronized (sWm.mWindowMap) {
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
+ attrs.setTitle(name);
- final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
- 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, mPowerManagerWrapper);
- // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
- // adding it to the token...
- token.addWindow(w);
- return w;
+ final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent,
+ OP_NONE,
+ 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
+ mPowerManagerWrapper);
+ // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
+ // adding it to the token...
+ token.addWindow(w);
+ return w;
+ }
}
/** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
TaskStack createTaskStackOnDisplay(DisplayContent dc) {
- return createStackControllerOnDisplay(dc).mContainer;
+ synchronized (sWm.mWindowMap) {
+ return createStackControllerOnDisplay(dc).mContainer;
+ }
}
StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
- return createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
+ synchronized (sWm.mWindowMap) {
+ return createStackControllerOnStackOnDisplay(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
+ }
}
StackWindowController createStackControllerOnStackOnDisplay(
int windowingMode, int activityType, DisplayContent dc) {
- final Configuration overrideConfig = new Configuration();
- overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
- overrideConfig.windowConfiguration.setActivityType(activityType);
- final int stackId = ++sNextStackId;
- final StackWindowController controller = new StackWindowController(stackId, null,
- dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
- controller.onOverrideConfigurationChanged(overrideConfig);
- return controller;
+ synchronized (sWm.mWindowMap) {
+ final Configuration overrideConfig = new Configuration();
+ overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
+ overrideConfig.windowConfiguration.setActivityType(activityType);
+ final int stackId = ++sNextStackId;
+ final StackWindowController controller = new StackWindowController(stackId, null,
+ dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
+ controller.onOverrideConfigurationChanged(overrideConfig);
+ return controller;
+ }
}
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
@@ -314,14 +345,18 @@
final int displayId = sNextDisplayId++;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- return new DisplayContent(display, sWm, mWallpaperController,
- mock(DisplayWindowController.class));
+ synchronized (sWm.mWindowMap) {
+ return new DisplayContent(display, sWm, mWallpaperController,
+ mock(DisplayWindowController.class));
+ }
}
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
WindowToken token) {
- return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
+ synchronized (sWm.mWindowMap) {
+ return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 394e636..e3b7174 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -49,7 +49,7 @@
@Test
public void testAddWindow() throws Exception {
final WindowTestUtils.TestWindowToken token =
- new WindowTestUtils.TestWindowToken(0, mDisplayContent);
+ WindowTestUtils.createTestWindowToken(0, mDisplayContent);
assertEquals(0, token.getWindowsCount());
@@ -79,7 +79,7 @@
@Test
public void testChildRemoval() throws Exception {
final DisplayContent dc = mDisplayContent;
- final WindowTestUtils.TestWindowToken token = new WindowTestUtils.TestWindowToken(0, dc);
+ final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, dc);
assertEquals(token, dc.getWindowToken(token.token));
@@ -102,9 +102,8 @@
*/
@Test
public void testTokenRemovalProcess() throws Exception {
- final WindowTestUtils.TestWindowToken token =
- new WindowTestUtils.TestWindowToken(TYPE_TOAST, mDisplayContent,
- true /* persistOnEmpty */);
+ final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(
+ TYPE_TOAST, mDisplayContent, true /* persistOnEmpty */);
// Verify that the token is on the display
assertNotNull(mDisplayContent.getWindowToken(token.token));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index 142041a..cfc7430 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -18,10 +18,13 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import android.app.ActivityManager;
import android.app.Notification;
@@ -149,4 +152,52 @@
assertFalse(r.canShowBadge());
}
+
+ @Test
+ public void testDndOverridesYes() {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setIntercepted(true);
+ r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_BADGE);
+
+ extractor.process(r);
+
+ assertFalse(r.canShowBadge());
+ }
+
+ @Test
+ public void testDndOConsidersInterception() {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setIntercepted(false);
+ r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_BADGE);
+
+ extractor.process(r);
+
+ assertTrue(r.canShowBadge());
+ }
+
+ @Test
+ public void testDndConsidersSuppressedVisualEffects() {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setIntercepted(true);
+ r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
+
+ extractor.process(r);
+
+ assertTrue(r.canShowBadge());
+ }
}
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 7b2c040..4fe54b9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -22,8 +22,19 @@
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.os.Build.VERSION_CODES.O_MR1;
+import static android.os.Build.VERSION_CODES.P;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -2530,4 +2541,125 @@
verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(message1.getDataUri()),
anyInt(), anyInt());
}
+
+ @Test
+ public void testSetNotificationPolicy_preP_setOldFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+ int expected = SUPPRESSED_EFFECT_BADGE
+ | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
+ | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_preP_setNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+
+ int expected = SUPPRESSED_EFFECT_BADGE;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_preP_setOldNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
+
+ int expected =
+ SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_P_setOldFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
+
+ int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
+ | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_P_setNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+
+ int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF
+ | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS
+ | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testSetNotificationPolicy_P_setOldNewFields() {
+ ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = mZenModeHelper;
+ NotificationManager.Policy userPolicy =
+ new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy);
+
+ NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
+
+ int expected = SUPPRESSED_EFFECT_STATUS_BAR;
+ int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+
+ appPolicy = new NotificationManager.Policy(0, 0, 0,
+ SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+
+ expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT
+ | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P);
+
+ assertEquals(expected, actual);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
index faba6b6..beff0d1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeExtractorTest.java
@@ -17,6 +17,8 @@
package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -57,6 +59,8 @@
assertFalse(r.isIntercepted());
when(mZenModeHelper.shouldIntercept(any())).thenReturn(true);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0,0,0));
extractor.process(r);
@@ -70,7 +74,8 @@
NotificationRecord r = generateRecord();
when(mZenModeHelper.shouldIntercept(any())).thenReturn(false);
- when(mZenModeHelper.shouldSuppressWhenScreenOff()).thenReturn(false);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0,0,0));
extractor.process(r);
@@ -84,13 +89,14 @@
NotificationRecord r = generateRecord();
when(mZenModeHelper.shouldIntercept(any())).thenReturn(true);
- when(mZenModeHelper.shouldSuppressWhenScreenOff()).thenReturn(true);
- when(mZenModeHelper.shouldSuppressWhenScreenOn()).thenReturn(true);
+ when(mZenModeHelper.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0,0,0, SUPPRESSED_EFFECT_PEEK
+ | SUPPRESSED_EFFECT_NOTIFICATION_LIST));
extractor.process(r);
- assertEquals(NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF
- | NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON,
+ assertEquals(NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK
+ | NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
r.getSuppressedVisualEffects());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
new file mode 100644
index 0000000..c0bd7cc
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 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 distriZenbuted 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.notification;
+
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.media.AudioAttributes;
+import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenModeConfig;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.util.NotificationMessagingUtil;
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ZenModeFilteringTest extends UiServiceTestCase {
+
+ @Mock
+ private NotificationMessagingUtil mMessagingUtil;
+ private ZenModeFiltering mZenModeFiltering;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mZenModeFiltering = new ZenModeFiltering(mContext, mMessagingUtil);
+ }
+
+ private NotificationRecord getNotificationRecord() {
+ return getNotificationRecord(mock(NotificationChannel.class));
+ }
+
+ private NotificationRecord getNotificationRecord(NotificationChannel c) {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getNotification()).thenReturn(mock(Notification.class));
+ return new NotificationRecord(mContext, sbn, c);
+ }
+
+ @Test
+ public void testIsMessage() {
+ NotificationRecord r = getNotificationRecord();
+
+ when(mMessagingUtil.isMessaging(any())).thenReturn(true);
+ assertTrue(mZenModeFiltering.isMessage(r));
+
+ when(mMessagingUtil.isMessaging(any())).thenReturn(false);
+ assertFalse(mZenModeFiltering.isMessage(r));
+ }
+
+ @Test
+ public void testIsAlarm() {
+ NotificationChannel c = mock(NotificationChannel.class);
+ when(c.getAudioAttributes()).thenReturn(new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ALARM)
+ .build());
+ NotificationRecord r = getNotificationRecord(c);
+ assertTrue(mZenModeFiltering.isAlarm(r));
+
+ r = getNotificationRecord();
+ r.sbn.getNotification().category = Notification.CATEGORY_ALARM;
+ assertTrue(mZenModeFiltering.isAlarm(r));
+ }
+
+ @Test
+ public void testIsAlarm_wrongCategory() {
+ NotificationRecord r = getNotificationRecord();
+ r.sbn.getNotification().category = Notification.CATEGORY_CALL;
+ assertFalse(mZenModeFiltering.isAlarm(r));
+ }
+
+ @Test
+ public void testIsAlarm_wrongUsage() {
+ NotificationChannel c = mock(NotificationChannel.class);
+ when(c.getAudioAttributes()).thenReturn(new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .build());
+ NotificationRecord r = getNotificationRecord(c);
+ assertFalse(mZenModeFiltering.isAlarm(r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_yes_VisEffectsAllowed() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects()
+ - SUPPRESSED_EFFECT_STATUS_BAR;
+
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_yes_WrongId() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_yes_WrongPackage() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android2");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressDNDInfo_no() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("android");
+ when(r.sbn.getId()).thenReturn(SystemMessage.NOTE_ZEN_UPGRADE);
+ ZenModeConfig config = mock(ZenModeConfig.class);
+ config.suppressedVisualEffects = NotificationManager.Policy.getAllSuppressedVisualEffects();
+
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config, r));
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_ALARMS, config, r));
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_NO_INTERRUPTIONS, config, r));
+ }
+
+ @Test
+ public void testSuppressAnything_yes_ZenModeOff() {
+ NotificationRecord r = getNotificationRecord();
+ when(r.sbn.getPackageName()).thenReturn("bananas");
+ ZenModeConfig config = mock(ZenModeConfig.class);
+
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_OFF, config, r));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 93c711c..9008803 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
@@ -34,6 +36,7 @@
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
@@ -48,8 +51,11 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.Xml;
+import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import android.util.Slog;
@@ -58,6 +64,13 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -80,12 +93,27 @@
mContext = spy(getContext());
mContentResolver = mContext.getContentResolver();
when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getString(R.string.zen_mode_default_every_night_name)).thenReturn("night");
+ when(mResources.getString(R.string.zen_mode_default_events_name)).thenReturn("events");
when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders));
}
+ private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup)
+ throws Exception {
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ serializer.startDocument(null, true);
+ mZenModeHelperSpy.writeXml(serializer, forBackup);
+ serializer.endDocument();
+ serializer.flush();
+ mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml");
+ return baos;
+ }
+
@Test
public void testZenOff_NoMuteApplied() {
mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF;
@@ -407,7 +435,7 @@
verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelperSpy.TAG);
- // 3. change ringer from normal to silent, verify previous ringer set to new rigner (silent)
+ // 3. change ringer from normal to silent, verify previous ringer set to new ringer (silent)
ZenModeHelper.RingerModeDelegate ringerModeDelegate =
mZenModeHelperSpy.new RingerModeDelegate();
ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
@@ -423,4 +451,145 @@
verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT,
mZenModeHelperSpy.TAG);
}
+
+ @Test
+ public void testSilentRingerSavedInZenOff_startsZenOff() {
+ AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
+ mZenModeHelperSpy.mAudioManager = mAudioManager;
+
+ // apply zen off multiple times - verify ringer is not set to normal
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+ mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelperSpy.mConfig = null; // will evaluate config to zen mode off
+ for (int i = 0; i < 3; i++) {
+ // if zen doesn't change, zen should not reapply itself to the ringer
+ mZenModeHelperSpy.evaluateZenMode("test", true);
+ }
+ verify(mZenModeHelperSpy, never()).applyZenToRingerMode();
+ verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
+ mZenModeHelperSpy.TAG);
+ }
+
+ @Test
+ public void testSilentRingerSavedOnZenOff_startsZenOn() {
+ AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
+ mZenModeHelperSpy.mAudioManager = mAudioManager;
+ mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF;
+
+ // previously set silent ringer
+ ZenModeHelper.RingerModeDelegate ringerModeDelegate =
+ mZenModeHelperSpy.new RingerModeDelegate();
+ ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
+ AudioManager.RINGER_MODE_SILENT, "test", AudioManager.RINGER_MODE_NORMAL,
+ VolumePolicy.DEFAULT);
+ assertEquals(AudioManager.RINGER_MODE_SILENT, Global.getInt(mContext.getContentResolver(),
+ Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL));
+
+ // apply zen off multiple times - verify ringer is not set to normal
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig = null; // will evaluate config to zen mode off
+ for (int i = 0; i < 3; i++) {
+ // if zen doesn't change, zen should not reapply itself to the ringer
+ mZenModeHelperSpy.evaluateZenMode("test", true);
+ }
+ verify(mZenModeHelperSpy, times(1)).applyZenToRingerMode();
+ verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
+ mZenModeHelperSpy.TAG);
+ }
+
+ @Test
+ public void testVibrateRingerSavedOnZenOff_startsZenOn() {
+ AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
+ mZenModeHelperSpy.mAudioManager = mAudioManager;
+ mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF;
+
+ // previously set silent ringer
+ ZenModeHelper.RingerModeDelegate ringerModeDelegate =
+ mZenModeHelperSpy.new RingerModeDelegate();
+ ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
+ AudioManager.RINGER_MODE_VIBRATE, "test", AudioManager.RINGER_MODE_NORMAL,
+ VolumePolicy.DEFAULT);
+ assertEquals(AudioManager.RINGER_MODE_VIBRATE, Global.getInt(mContext.getContentResolver(),
+ Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL));
+
+ // apply zen off multiple times - verify ringer is not set to normal
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig = null; // will evaluate config to zen mode off
+ for (int i = 0; i < 3; i++) {
+ // if zen doesn't change, zen should not reapply itself to the ringer
+ mZenModeHelperSpy.evaluateZenMode("test", true);
+ }
+ verify(mZenModeHelperSpy, times(1)).applyZenToRingerMode();
+ verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
+ mZenModeHelperSpy.TAG);
+ }
+
+ @Test
+ public void testParcelConfig() {
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.allowAlarms = false;
+ mZenModeHelperSpy.mConfig.allowMedia = false;
+ mZenModeHelperSpy.mConfig.allowSystem = false;
+ mZenModeHelperSpy.mConfig.allowReminders = true;
+ mZenModeHelperSpy.mConfig.allowCalls = true;
+ mZenModeHelperSpy.mConfig.allowMessages = true;
+ mZenModeHelperSpy.mConfig.allowEvents = true;
+ mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+
+ ZenModeConfig actual = mZenModeHelperSpy.mConfig.copy();
+
+ assertEquals(mZenModeHelperSpy.mConfig, actual);
+ }
+
+ @Test
+ public void testWriteXml() throws Exception {
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.allowAlarms = false;
+ mZenModeHelperSpy.mConfig.allowMedia = false;
+ mZenModeHelperSpy.mConfig.allowSystem = false;
+ mZenModeHelperSpy.mConfig.allowReminders = true;
+ mZenModeHelperSpy.mConfig.allowCalls = true;
+ mZenModeHelperSpy.mConfig.allowMessages = true;
+ mZenModeHelperSpy.mConfig.allowEvents = true;
+ mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ mZenModeHelperSpy.mConfig.manualRule.zenMode =
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+
+ ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(false);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(expected, mZenModeHelperSpy.mConfig);
+ }
+
+ @Test
+ public void testPolicyReadsSuppressedEffects() {
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+
+ NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
+ assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a302578..3c371e5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -506,6 +506,7 @@
IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
boolean checkin = false;
+ boolean compact = false;
String pkg = null;
if (args != null) {
@@ -513,6 +514,9 @@
String arg = args[i];
if ("--checkin".equals(arg)) {
checkin = true;
+ } else
+ if ("-c".equals(arg)) {
+ compact = true;
} else if ("flush".equals(arg)) {
flushToDiskLocked();
pw.println("Flushed stats to disk");
@@ -534,7 +538,7 @@
if (checkin) {
mUserState.valueAt(i).checkin(idpw);
} else {
- mUserState.valueAt(i).dump(idpw, pkg);
+ mUserState.valueAt(i).dump(idpw, pkg, compact);
idpw.println();
}
mAppStandby.dumpUser(idpw, userId, pkg);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 29c5ee8..836eb31 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -47,7 +47,7 @@
class UserUsageStatsService {
private static final String TAG = "UsageStatsService";
private static final boolean DEBUG = UsageStatsService.DEBUG;
- private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss");
+ private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final int sDateFormatFlags =
DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_TIME
@@ -516,25 +516,28 @@
mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
@Override
public boolean checkin(IntervalStats stats) {
- printIntervalStats(pw, stats, true, null);
+ printIntervalStats(pw, stats, false, false, null);
return true;
}
});
}
void dump(IndentingPrintWriter pw, String pkg) {
- printLast24HrEvents(pw, true, pkg);
+ dump(pw, pkg, false);
+ }
+ void dump(IndentingPrintWriter pw, String pkg, boolean compact) {
+ printLast24HrEvents(pw, !compact, pkg);
for (int interval = 0; interval < mCurrentStats.length; interval++) {
pw.print("In-memory ");
pw.print(intervalToString(interval));
pw.println(" stats");
- printIntervalStats(pw, mCurrentStats[interval], false, pkg);
+ printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg);
}
}
private String formatDateTime(long dateTime, boolean pretty) {
if (pretty) {
- return "\"" + DateFormat.format("yyyy-MM-dd HH:mm:ss", dateTime).toString() + "\"";
+ return "\"" + sDateFormat.format(dateTime)+ "\"";
}
return Long.toString(dateTime);
}
@@ -623,8 +626,7 @@
}
void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
- boolean checkin, String pkg) {
- boolean prettyDates = !checkin;
+ boolean prettyDates, boolean skipEvents, String pkg) {
if (prettyDates) {
pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
@@ -699,7 +701,7 @@
// The last 24 hours of events is already printed in the non checkin dump
// No need to repeat here.
- if (checkin) {
+ if (!skipEvents) {
pw.println("events");
pw.increaseIndent();
final TimeSparseArray<UsageEvents.Event> events = stats.events;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a79f2c9..73243d2 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -879,42 +879,76 @@
/**
* @hide
*/
- @IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
- HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED,
- HANDOVER_FAILURE_ONGOING_EMERG_CALL})
+ @IntDef(prefix = { "HANDOVER_" },
+ value = {HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_NOT_SUPPORTED,
+ HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERG_CALL,
+ HANDOVER_FAILURE_UNKNOWN})
@Retention(RetentionPolicy.SOURCE)
public @interface HandoverFailureErrors {}
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
- * to handover the call rejects handover.
+ * to handover the call to rejects the handover request.
+ * <p>
+ * Will be returned when {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} is called
+ * and the destination {@link PhoneAccountHandle}'s {@link ConnectionService} returns a
+ * {@code null} {@link Connection} from
+ * {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle,
+ * ConnectionRequest)}.
+ * <p>
+ * For more information on call handovers, see
+ * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
/**
- * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there is
- * an error associated with unsupported handover.
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
+ * is initiated but the source or destination app does not support handover.
+ * <p>
+ * Will be returned when a handover is requested via
+ * {@link #handoverTo(PhoneAccountHandle, int, Bundle)} and the destination
+ * {@link PhoneAccountHandle} does not declare
+ * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}. May also be returned when a handover is
+ * requested at the {@link PhoneAccountHandle} for the current call (i.e. the source call's
+ * {@link Details#getAccountHandle()}) does not declare
+ * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}.
+ * <p>
+ * For more information on call handovers, see
+ * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
- public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2;
+ public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2;
/**
- * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
- * are some permission errors associated with APIs doing handover.
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the remote
+ * user rejects the handover request.
+ * <p>
+ * For more information on call handovers, see
+ * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
- public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3;
-
- /**
- * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when user
- * rejects handover.
- */
- public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+ public static final int HANDOVER_FAILURE_USER_REJECTED = 3;
/**
* Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
* is ongoing emergency call.
+ * <p>
+ * This error code is returned when {@link #handoverTo(PhoneAccountHandle, int, Bundle)} is
+ * called on an emergency call, or if any other call is an emergency call.
+ * <p>
+ * Handovers are not permitted while there are ongoing emergency calls.
+ * <p>
+ * For more information on call handovers, see
+ * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
*/
- public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 5;
+ public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 4;
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
+ * fails for an unknown reason.
+ * <p>
+ * For more information on call handovers, see
+ * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
+ */
+ public static final int HANDOVER_FAILURE_UNKNOWN = 5;
/**
* Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
@@ -1055,6 +1089,10 @@
/**
* Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
* has completed successfully.
+ * <p>
+ * For a full discussion of the handover process and the APIs involved, see
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
+ *
* @param call The call which had initiated handover.
*/
public void onHandoverComplete(Call call) {}
@@ -1062,8 +1100,12 @@
/**
* Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
* has failed.
+ * <p>
+ * For a full discussion of the handover process and the APIs involved, see
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
+ *
* @param call The call which had initiated handover.
- * @param failureReason Error reason for failure
+ * @param failureReason Error reason for failure.
*/
public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
}
@@ -1260,7 +1302,7 @@
* Instructs this {@link #STATE_RINGING} {@code Call} to answer.
* @param videoState The video state in which to answer the call.
*/
- public void answer(int videoState) {
+ public void answer(@VideoProfile.VideoState int videoState) {
mInCallAdapter.answerCall(mTelecomCallId, videoState);
}
@@ -1474,16 +1516,65 @@
* by {@code toHandle}. The videoState specified indicates the desired video state after the
* handover.
* <p>
- * A handover request is initiated by the user from one app to indicate a desire
- * to handover a call to another.
+ * A call handover is the process where an ongoing call is transferred from one app (i.e.
+ * {@link ConnectionService} to another app. The user could, for example, choose to continue a
+ * mobile network call in a video calling app. The mobile network call via the Telephony stack
+ * is referred to as the source of the handover, and the video calling app is referred to as the
+ * destination.
+ * <p>
+ * When considering a handover scenario the device this method is called on is considered the
+ * <em>initiating</em> device (since the user initiates the handover from this device), and the
+ * other device is considered the <em>receiving</em> device.
+ * <p>
+ * When this method is called on the <em>initiating</em> device, the Telecom framework will bind
+ * to the {@link ConnectionService} defined by the {@code toHandle} {@link PhoneAccountHandle}
+ * and invoke
+ * {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle,
+ * ConnectionRequest)} to inform the destination app that a request has been made to handover a
+ * call to it. The app returns an instance of {@link Connection} to represent the handover call
+ * At this point the app should display UI to indicate to the user that a call
+ * handover is in process.
+ * <p>
+ * The destination app is responsible for communicating the handover request from the
+ * <em>initiating</em> device to the <em>receiving</em> device.
+ * <p>
+ * When the app on the <em>receiving</em> device receives the handover request, it calls
+ * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} to continue the handover
+ * process from the <em>initiating</em> device to the <em>receiving</em> device. At this point
+ * the destination app on the <em>receiving</em> device should show UI to allow the user to
+ * choose whether they want to continue their call in the destination app.
+ * <p>
+ * When the destination app on the <em>receiving</em> device calls
+ * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}, Telecom will bind to its
+ * {@link ConnectionService} and call
+ * {@link ConnectionService#onCreateIncomingHandoverConnection(PhoneAccountHandle,
+ * ConnectionRequest)} to inform it of the handover request. The app returns an instance of
+ * {@link Connection} to represent the handover call.
+ * <p>
+ * If the user of the <em>receiving</em> device accepts the handover, the app calls
+ * {@link Connection#setActive()} to complete the handover process; Telecom will disconnect the
+ * original call. If the user rejects the handover, the app calls
+ * {@link Connection#setDisconnected(DisconnectCause)} and specifies a {@link DisconnectCause}
+ * of {@link DisconnectCause#CANCELED} to indicate that the handover has been cancelled.
+ * <p>
+ * Telecom will only allow handovers from {@link PhoneAccount}s which declare
+ * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}. Similarly, the {@link PhoneAccount}
+ * specified by {@code toHandle} must declare {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}.
+ * <p>
+ * Errors in the handover process are reported to the {@link InCallService} via
+ * {@link Callback#onHandoverFailed(Call, int)}. Errors in the handover process are reported to
+ * the involved {@link ConnectionService}s via
+ * {@link ConnectionService#onHandoverFailed(ConnectionRequest, int)}.
*
* @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
* this call to.
- * @param videoState Indicates the video state desired after the handover.
+ * @param videoState Indicates the video state desired after the handover (see the
+ * {@code STATE_*} constants defined in {@link VideoProfile}).
* @param extras Bundle containing extra information to be passed to the
* {@link ConnectionService}
*/
- public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) {
+ public void handoverTo(PhoneAccountHandle toHandle, @VideoProfile.VideoState int videoState,
+ Bundle extras) {
mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index ffa0c94..fc32b17 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2219,12 +2219,50 @@
}
/**
- * Called by Telecom on the initiating side of the handover to create an instance of a
- * handover connection.
+ * Called by Telecom to request that a {@link ConnectionService} creates an instance of an
+ * outgoing handover {@link Connection}.
+ * <p>
+ * A call handover is the process where an ongoing call is transferred from one app (i.e.
+ * {@link ConnectionService} to another app. The user could, for example, choose to continue a
+ * mobile network call in a video calling app. The mobile network call via the Telephony stack
+ * is referred to as the source of the handover, and the video calling app is referred to as the
+ * destination.
+ * <p>
+ * When considering a handover scenario the <em>initiating</em> device is where a user initiated
+ * the handover process (e.g. by calling {@link android.telecom.Call#handoverTo(
+ * PhoneAccountHandle, int, Bundle)}, and the other device is considered the <em>receiving</em>
+ * device.
+ * <p>
+ * This method is called on the destination {@link ConnectionService} on <em>initiating</em>
+ * device when the user initiates a handover request from one app to another. The user request
+ * originates in the {@link InCallService} via
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
+ * <p>
+ * For a full discussion of the handover process and the APIs involved, see
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
+ * <p>
+ * Implementations of this method should return an instance of {@link Connection} which
+ * represents the handover. If your app does not wish to accept a handover to it at this time,
+ * you can return {@code null}. The code below shows an example of how this is done.
+ * <pre>
+ * {@code
+ * public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle
+ * fromPhoneAccountHandle, ConnectionRequest request) {
+ * if (!isHandoverAvailable()) {
+ * return null;
+ * }
+ * MyConnection connection = new MyConnection();
+ * connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+ * connection.setVideoState(request.getVideoState());
+ * return connection;
+ * }
+ * }
+ * </pre>
+ *
* @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
* ConnectionService which needs to handover the call.
- * @param request Details about the call which needs to be handover.
- * @return Connection object corresponding to the handover call.
+ * @param request Details about the call to handover.
+ * @return {@link Connection} instance corresponding to the handover call.
*/
public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
ConnectionRequest request) {
@@ -2232,12 +2270,46 @@
}
/**
- * Called by Telecom on the receiving side of the handover to request the
- * {@link ConnectionService} to create an instance of a handover connection.
+ * Called by Telecom to request that a {@link ConnectionService} creates an instance of an
+ * incoming handover {@link Connection}.
+ * <p>
+ * A call handover is the process where an ongoing call is transferred from one app (i.e.
+ * {@link ConnectionService} to another app. The user could, for example, choose to continue a
+ * mobile network call in a video calling app. The mobile network call via the Telephony stack
+ * is referred to as the source of the handover, and the video calling app is referred to as the
+ * destination.
+ * <p>
+ * When considering a handover scenario the <em>initiating</em> device is where a user initiated
+ * the handover process (e.g. by calling {@link android.telecom.Call#handoverTo(
+ * PhoneAccountHandle, int, Bundle)}, and the other device is considered the <em>receiving</em>
+ * device.
+ * <p>
+ * This method is called on the destination app on the <em>receiving</em> device when the
+ * destination app calls {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} to
+ * accept an incoming handover from the <em>initiating</em> device.
+ * <p>
+ * For a full discussion of the handover process and the APIs involved, see
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
+ * <p>
+ * Implementations of this method should return an instance of {@link Connection} which
+ * represents the handover. The code below shows an example of how this is done.
+ * <pre>
+ * {@code
+ * public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle
+ * fromPhoneAccountHandle, ConnectionRequest request) {
+ * // Given that your app requested to accept the handover, you should not return null here.
+ * MyConnection connection = new MyConnection();
+ * connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+ * connection.setVideoState(request.getVideoState());
+ * return connection;
+ * }
+ * }
+ * </pre>
+ *
* @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
* ConnectionService which needs to handover the call.
* @param request Details about the call which needs to be handover.
- * @return {@link Connection} object corresponding to the handover call.
+ * @return {@link Connection} instance corresponding to the handover call.
*/
public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
ConnectionRequest request) {
@@ -2247,11 +2319,15 @@
/**
* Called by Telecom in response to a {@code TelecomManager#acceptHandover()}
* invocation which failed.
- * @param request Details about the call which needs to be handover.
- * @param error Reason for handover failure as defined in
- * {@link android.telecom.Call.Callback#HANDOVER_FAILURE_DEST_INVALID_PERM}
+ * <p>
+ * For a full discussion of the handover process and the APIs involved, see
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}
+ *
+ * @param request Details about the call which failed to handover.
+ * @param error Reason for handover failure. Will be one of the
*/
- public void onHandoverFailed(ConnectionRequest request, int error) {
+ public void onHandoverFailed(ConnectionRequest request,
+ @Call.Callback.HandoverFailureErrors int error) {
return;
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 59ce590..bb4b483 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -93,6 +93,10 @@
// failure on the providing end, so immediately mark it destroyed
connection.setDestroyed();
}
+ connection.setStatusHints(parcel.getStatusHints());
+ connection.setIsVoipAudioMode(parcel.getIsVoipAudioMode());
+ connection.setRingbackRequested(parcel.isRingbackRequested());
+ connection.putExtras(parcel.getExtras());
}
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e456830..72c67d3 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1794,8 +1794,25 @@
}
/**
- * Called from the recipient side of a handover to indicate a desire to accept the handover
- * of an ongoing call to another {@link ConnectionService} identified by
+ * Called by an app to indicate that it wishes to accept the handover of an ongoing call to a
+ * {@link PhoneAccountHandle} it defines.
+ * <p>
+ * A call handover is the process where an ongoing call is transferred from one app (i.e.
+ * {@link ConnectionService} to another app. The user could, for example, choose to continue a
+ * mobile network call in a video calling app. The mobile network call via the Telephony stack
+ * is referred to as the source of the handover, and the video calling app is referred to as the
+ * destination.
+ * <p>
+ * When considering a handover scenario the <em>initiating</em> device is where a user initiated
+ * the handover process (e.g. by calling {@link android.telecom.Call#handoverTo(
+ * PhoneAccountHandle, int, Bundle)}, and the other device is considered the <em>receiving</em>
+ * device.
+ * <p>
+ * For a full discussion of the handover process and the APIs involved, see
+ * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
+ * <p>
+ * This method is called from the <em>receiving</em> side of a handover to indicate a desire to
+ * accept the handover of an ongoing call to another {@link ConnectionService} identified by
* {@link PhoneAccountHandle} destAcct. For managed {@link ConnectionService}s, the specified
* {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
* the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
@@ -1819,7 +1836,8 @@
* @param videoState Video state after the handover.
* @param destAcct The {@link PhoneAccountHandle} registered to the calling package.
*/
- public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) {
+ public void acceptHandover(Uri srcAddr, @VideoProfile.VideoState int videoState,
+ PhoneAccountHandle destAcct) {
try {
if (isServiceConnected()) {
getTelecomService().acceptHandover(srcAddr, videoState, destAcct);
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index e0e3a08..90ed36f 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -62,6 +62,7 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(
flag = true,
+ prefix = { "STATE_" },
value = {STATE_AUDIO_ONLY, STATE_TX_ENABLED, STATE_RX_ENABLED, STATE_BIDIRECTIONAL,
STATE_PAUSED})
public @interface VideoState {}
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 7cd1612..cac9f2b 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -30,6 +30,9 @@
public static final int EUTRAN = 3;
public static final int CDMA2000 = 4;
public static final int IWLAN = 5;
+
+ /** @hide */
+ private AccessNetworkType() {};
}
/**
@@ -42,6 +45,9 @@
public static final int WWAN = 1;
/** Wireless Local Area Networks (i.e. Wifi) */
public static final int WLAN = 2;
+
+ /** @hide */
+ private TransportType() {};
}
/**
@@ -63,6 +69,9 @@
public static final int BAND_DCS1800 = 12;
public static final int BAND_PCS1900 = 13;
public static final int BAND_ER900 = 14;
+
+ /** @hide */
+ private GeranBand() {};
}
/**
@@ -92,6 +101,9 @@
/** band 23, 24 are reserved */
public static final int BAND_25 = 25;
public static final int BAND_26 = 26;
+
+ /** @hide */
+ private UtranBand() {};
}
/**
@@ -147,6 +159,9 @@
public static final int BAND_66 = 66;
public static final int BAND_68 = 68;
public static final int BAND_70 = 70;
+
+ /** @hide */
+ private EutranBand() {};
}
/**
@@ -179,5 +194,11 @@
public static final int BAND_19 = 20;
public static final int BAND_20 = 21;
public static final int BAND_21 = 22;
+
+ /** @hide */
+ private CdmaBands() {};
}
+
+ /** @hide */
+ private AccessNetworkConstants() {};
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d43db32..eebe2a1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1285,13 +1285,38 @@
/**
* The duration in seconds that platform call and message blocking is disabled after the user
- * contacts emergency services. Platform considers values in the range 0 to 604800 (one week) as
- * valid. See {@link android.provider.BlockedNumberContract#isBlocked(Context, String)}).
+ * contacts emergency services. Platform considers values for below cases:
+ * 1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly.
+ * 2) VALUE > 604800(one week): will use the default value as duration instead.
+ * 3) VALUE < 0: block will be disabled forever until user re-eanble block manually,
+ * the suggested value to disable forever is -1.
+ * See {@code android.provider.BlockedNumberContract#notifyEmergencyContact(Context)}
+ * See {@code android.provider.BlockedNumberContract#isBlocked(Context, String)}.
*/
public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT =
"duration_blocking_disabled_after_emergency_int";
/**
+ * Determines whether to enable enhanced call blocking feature on the device.
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
+ *
+ * <p>
+ * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml
+ * and vendor.xml.
+ * <p>
+ * 2. For Dual SIM(DS) device, it should be customized in vendor.xml, since call blocking
+ * function is used regardless of SIM.
+ * <p>
+ * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL =
+ "support_enhanced_call_blocking_bool";
+
+ /**
* For carriers which require an empty flash to be sent before sending the normal 3-way calling
* flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty
* flash is sent.
@@ -2052,6 +2077,7 @@
sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, false);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index a277212..7f43ee5 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -29,9 +29,9 @@
/**
* The caller of
- * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, NetworkScanCallback)}
+ * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, Executor, NetworkScanCallback)}
* will receive an instance of {@link NetworkScan}, which contains a callback method
- * {@link #stop()} for stopping the in-progress scan.
+ * {@link #stopScan()} for stopping the in-progress scan.
*/
public class NetworkScan {
@@ -106,16 +106,24 @@
* Use this method to stop an ongoing scan. When user requests a new scan, a {@link NetworkScan}
* object will be returned, and the user can stop the scan by calling this method.
*/
- public void stop() throws RemoteException {
+ public void stopScan() {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ Rlog.e(TAG, "Failed to get the ITelephony instance.");
+ }
try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- telephony.stopNetworkScan(mSubId, mScanId);
- } else {
- throw new RemoteException("Failed to get the ITelephony instance.");
- }
+ telephony.stopNetworkScan(mSubId, mScanId);
} catch (RemoteException ex) {
Rlog.e(TAG, "stopNetworkScan RemoteException", ex);
+ }
+ }
+
+ /** @deprecated Use {@link #stopScan()} */
+ @Deprecated
+ public void stop() throws RemoteException {
+ try {
+ stopScan();
+ } catch (RuntimeException ex) {
throw new RemoteException("Failed to stop the network scan with id " + mScanId);
}
}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index ea2b0ae..4e56396 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -161,6 +161,7 @@
mTdScdmaRscp = INVALID;
mWcdmaSignalStrength = 99;
mWcdmaRscp = INVALID;
+ mWcdmaRscpAsu = 255;
mLteRsrpBoost = 0;
mIsGsm = gsmFlag;
mUseOnlyRsrpForLteLevel = false;
@@ -383,7 +384,7 @@
// but are reported in ASU which is 0 through 96, so we do the conversion here
mWcdmaRscpAsu =
((mWcdmaRscpAsu - 120 >= MIN_WCDMA_RSCP) && (mWcdmaRscpAsu - 120 <= MAX_WCDMA_RSCP))
- ? mWcdmaRscpAsu : INVALID;
+ ? mWcdmaRscpAsu : 255;
mWcdmaRscp = ((mWcdmaRscp >= MIN_WCDMA_RSCP) && (mWcdmaRscp <= MAX_WCDMA_RSCP))
? mWcdmaRscp : INVALID;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index af3a0bb..aa76e9d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -34,6 +34,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.Handler;
@@ -74,6 +75,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -2754,18 +2756,17 @@
* @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
* IMSI and IMPI. This includes the public key and the key identifier. This information
* will be stored in the device keystore. The system will return a null when no key was
- * found, and the carrier does not require a key. The system will throw the following
- * exceptions:
- * 1. IllegalArgumentException when an invalid key is sent.
- * 2. RuntimeException if the key is required but not found; and also if there was an
- * internal exception.
+ * found, and the carrier does not require a key. The system will throw
+ * IllegalArgumentException when an invalid key is sent or when key is required but
+ * not found.
* @hide
*/
public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null) {
- throw new RuntimeException("IMSI error: Subscriber Info is null");
+ Rlog.e(TAG,"IMSI error: Subscriber Info is null");
+ return null;
}
int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
if (keyType != KEY_TYPE_EPDG && keyType != KEY_TYPE_WLAN) {
@@ -2773,20 +2774,18 @@
}
ImsiEncryptionInfo imsiEncryptionInfo = info.getCarrierInfoForImsiEncryption(
subId, keyType, mContext.getOpPackageName());
- if (imsiEncryptionInfo == null
- && isImsiEncryptionRequired(subId, keyType)) {
+ if (imsiEncryptionInfo == null && isImsiEncryptionRequired(subId, keyType)) {
Rlog.e(TAG, "IMSI error: key is required but not found");
- throw new RuntimeException("IMSI error: key is required but not found");
+ throw new IllegalArgumentException("IMSI error: key is required but not found");
}
return imsiEncryptionInfo;
} catch (RemoteException ex) {
Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
- throw new RuntimeException("IMSI error: Remote Exception");
} catch (NullPointerException ex) {
// This could happen before phone restarts due to crashing
Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
- throw new RuntimeException("IMSI error: Null Pointer exception");
}
+ return null;
}
/**
@@ -2802,17 +2801,16 @@
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null) {
- throw new RuntimeException("IMSI error: Subscriber Info is null");
+ Rlog.e(TAG, "IMSI error: Subscriber Info is null");
+ return;
}
int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
info.resetCarrierKeysForImsiEncryption(subId, mContext.getOpPackageName());
} catch (RemoteException ex) {
Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
- throw new RuntimeException("IMSI error: Remote Exception");
} catch (NullPointerException ex) {
// This could happen before phone restarts due to crashing
Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
- throw new RuntimeException("IMSI error: Null Pointer exception");
}
}
@@ -3788,8 +3786,6 @@
*
* @throws SecurityException if the caller does not have carrier privileges or is not the
* current default dialer
- *
- * @throws IllegalStateException if telephony service is unavailable.
*/
public void sendDialerSpecialCode(String inputCode) {
try {
@@ -3797,10 +3793,8 @@
telephony.sendDialerSpecialCode(mContext.getOpPackageName(), inputCode);
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowFromSystemServer();
} catch (NullPointerException ex) {
// This could happen before phone restarts due to crashing
- throw new IllegalStateException("Telephony service unavailable");
}
}
@@ -4925,10 +4919,10 @@
String v = android.provider.Settings.Global.getString(cr, name);
if (index == Integer.MAX_VALUE) {
- throw new RuntimeException("putIntAtIndex index == MAX_VALUE index=" + index);
+ throw new IllegalArgumentException("putIntAtIndex index == MAX_VALUE index=" + index);
}
if (index < 0) {
- throw new RuntimeException("putIntAtIndex index < 0 index=" + index);
+ throw new IllegalArgumentException("putIntAtIndex index < 0 index=" + index);
}
if (v != null) {
valArray = v.split(",");
@@ -5394,21 +5388,36 @@
* <p>
* Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * Or the calling app has carrier privileges.
+ * @see #hasCarrierPrivileges()
*
* @param request Contains all the RAT with bands/channels that need to be scanned.
+ * @param executor The executor through which the callback should be invoked.
* @param callback Returns network scan results or errors.
* @return A NetworkScan obj which contains a callback which can be used to stop the scan.
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public NetworkScan requestNetworkScan(
- NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
+ NetworkScanRequest request, Executor executor,
+ TelephonyScanManager.NetworkScanCallback callback) {
synchronized (this) {
if (mTelephonyScanManager == null) {
mTelephonyScanManager = new TelephonyScanManager();
}
}
- return mTelephonyScanManager.requestNetworkScan(getSubId(), request, callback);
+ return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback);
+ }
+
+ /**
+ * @deprecated
+ * Use {@link
+ * #requestNetworkScan(NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}
+ */
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public NetworkScan requestNetworkScan(
+ NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
+ return requestNetworkScan(request, AsyncTask.THREAD_POOL_EXECUTOR, callback);
}
/**
@@ -7210,7 +7219,6 @@
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowAsRuntimeException();
}
return UNKNOWN_CARRIER_ID;
}
@@ -7235,7 +7243,6 @@
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowAsRuntimeException();
}
return null;
}
@@ -7759,7 +7766,6 @@
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowAsRuntimeException();
}
}
}
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index c182e34..946cecf 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -33,6 +33,7 @@
import android.util.SparseArray;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
import com.android.internal.telephony.ITelephony;
@@ -55,8 +56,10 @@
/**
* The caller of
- * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should
- * implement and provide this callback so that the scan results or errors can be returned.
+ * {@link
+ * TelephonyManager#requestNetworkScan(NetworkScanRequest, Executor, NetworkScanCallback)}
+ * should implement and provide this callback so that the scan results or errors can be
+ * returned.
*/
public static abstract class NetworkScanCallback {
/** Returns the scan results to the user, this callback will be called multiple times. */
@@ -83,10 +86,13 @@
private static class NetworkScanInfo {
private final NetworkScanRequest mRequest;
+ private final Executor mExecutor;
private final NetworkScanCallback mCallback;
- NetworkScanInfo(NetworkScanRequest request, NetworkScanCallback callback) {
+ NetworkScanInfo(
+ NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
mRequest = request;
+ mExecutor = executor;
mCallback = callback;
}
}
@@ -112,10 +118,15 @@
"Failed to find NetworkScanInfo with id " + message.arg2);
}
NetworkScanCallback callback = nsi.mCallback;
+ Executor executor = nsi.mExecutor;
if (callback == null) {
throw new RuntimeException(
"Failed to find NetworkScanCallback with id " + message.arg2);
}
+ if (executor == null) {
+ throw new RuntimeException(
+ "Failed to find Executor with id " + message.arg2);
+ }
switch (message.what) {
case CALLBACK_SCAN_RESULTS:
@@ -126,21 +137,22 @@
for (int i = 0; i < parcelables.length; i++) {
ci[i] = (CellInfo) parcelables[i];
}
- callback.onResults((List<CellInfo>) Arrays.asList(ci));
+ executor.execute(() ->
+ callback.onResults((List<CellInfo>) Arrays.asList(ci)));
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onResults", e);
}
break;
case CALLBACK_SCAN_ERROR:
try {
- callback.onError(message.arg1);
+ executor.execute(() -> callback.onError(message.arg1));
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onError", e);
}
break;
case CALLBACK_SCAN_COMPLETE:
try {
- callback.onComplete();
+ executor.execute(() -> callback.onComplete());
mScanInfo.remove(message.arg2);
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onComplete", e);
@@ -171,12 +183,12 @@
* @hide
*/
public NetworkScan requestNetworkScan(int subId,
- NetworkScanRequest request, NetworkScanCallback callback) {
+ NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
int scanId = telephony.requestNetworkScan(subId, request, mMessenger, new Binder());
- saveScanInfo(scanId, request, callback);
+ saveScanInfo(scanId, request, executor, callback);
return new NetworkScan(scanId, subId);
}
} catch (RemoteException ex) {
@@ -187,9 +199,10 @@
return null;
}
- private void saveScanInfo(int id, NetworkScanRequest request, NetworkScanCallback callback) {
+ private void saveScanInfo(
+ int id, NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
synchronized (mScanInfo) {
- mScanInfo.put(id, new NetworkScanInfo(request, callback));
+ mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
}
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 27e5f94..350dfe3 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -296,7 +296,10 @@
readFromParcel(in);
}
- /** @hide */
+ /**
+ * Default Constructor that initializes the call profile with service type
+ * {@link #SERVICE_TYPE_NORMAL} and call type {@link #CALL_TYPE_VIDEO_N_VOICE}
+ */
public ImsCallProfile() {
mServiceType = SERVICE_TYPE_NORMAL;
mCallType = CALL_TYPE_VOICE_N_VIDEO;
@@ -304,7 +307,25 @@
mMediaProfile = new ImsStreamMediaProfile();
}
- /** @hide */
+ /**
+ * Constructor.
+ *
+ * @param serviceType the service type for the call. Can be one of the following:
+ * {@link #SERVICE_TYPE_NONE},
+ * {@link #SERVICE_TYPE_NORMAL},
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ * @param callType the call type. Can be one of the following:
+ * {@link #CALL_TYPE_VOICE_N_VIDEO},
+ * {@link #CALL_TYPE_VOICE},
+ * {@link #CALL_TYPE_VIDEO_N_VOICE},
+ * {@link #CALL_TYPE_VT},
+ * {@link #CALL_TYPE_VT_TX},
+ * {@link #CALL_TYPE_VT_RX},
+ * {@link #CALL_TYPE_VT_NODIR},
+ * {@link #CALL_TYPE_VS},
+ * {@link #CALL_TYPE_VS_TX},
+ * {@link #CALL_TYPE_VS_RX}
+ */
public ImsCallProfile(int serviceType, int callType) {
mServiceType = serviceType;
mCallType = callType;
@@ -312,6 +333,35 @@
mMediaProfile = new ImsStreamMediaProfile();
}
+ /**
+ * Constructor.
+ *
+ * @param serviceType the service type for the call. Can be one of the following:
+ * {@link #SERVICE_TYPE_NONE},
+ * {@link #SERVICE_TYPE_NORMAL},
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ * @param callType the call type. Can be one of the following:
+ * {@link #CALL_TYPE_VOICE_N_VIDEO},
+ * {@link #CALL_TYPE_VOICE},
+ * {@link #CALL_TYPE_VIDEO_N_VOICE},
+ * {@link #CALL_TYPE_VT},
+ * {@link #CALL_TYPE_VT_TX},
+ * {@link #CALL_TYPE_VT_RX},
+ * {@link #CALL_TYPE_VT_NODIR},
+ * {@link #CALL_TYPE_VS},
+ * {@link #CALL_TYPE_VS_TX},
+ * {@link #CALL_TYPE_VS_RX}
+ * @param callExtras A bundle with the call extras.
+ * @param mediaProfile The IMS stream media profile.
+ */
+ public ImsCallProfile(int serviceType, int callType, Bundle callExtras,
+ ImsStreamMediaProfile mediaProfile) {
+ mServiceType = serviceType;
+ mCallType = callType;
+ mCallExtras = callExtras;
+ mMediaProfile = mediaProfile;
+ }
+
public String getCallExtra(String name) {
return getCallExtra(name, "");
}
@@ -375,6 +425,16 @@
mCallExtras = (Bundle) profile.mCallExtras.clone();
}
+ /**
+ * Updates the media profile for the call.
+ *
+ * @param profile Call profile with new media profile.
+ */
+ public void updateMediaProfile(ImsCallProfile profile) {
+ mMediaProfile = profile.mMediaProfile;
+ }
+
+
@Override
public String toString() {
return "{ serviceType=" + mServiceType +
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 243352b..137106a 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -99,6 +99,62 @@
readFromParcel(in);
}
+ /**
+ * Constructor.
+ *
+ * @param audioQuality The audio quality. Can be one of the following:
+ * {@link #AUDIO_QUALITY_AMR},
+ * {@link #AUDIO_QUALITY_AMR_WB},
+ * {@link #AUDIO_QUALITY_QCELP13K},
+ * {@link #AUDIO_QUALITY_EVRC},
+ * {@link #AUDIO_QUALITY_EVRC_B},
+ * {@link #AUDIO_QUALITY_EVRC_WB},
+ * {@link #AUDIO_QUALITY_EVRC_NW},
+ * {@link #AUDIO_QUALITY_GSM_EFR},
+ * {@link #AUDIO_QUALITY_GSM_FR},
+ * {@link #AUDIO_QUALITY_GSM_HR},
+ * {@link #AUDIO_QUALITY_G711U},
+ * {@link #AUDIO_QUALITY_G723},
+ * {@link #AUDIO_QUALITY_G711A},
+ * {@link #AUDIO_QUALITY_G722},
+ * {@link #AUDIO_QUALITY_G711AB},
+ * {@link #AUDIO_QUALITY_G729},
+ * {@link #AUDIO_QUALITY_EVS_NB},
+ * {@link #AUDIO_QUALITY_EVS_WB},
+ * {@link #AUDIO_QUALITY_EVS_SWB},
+ * {@link #AUDIO_QUALITY_EVS_FB},
+ * @param audioDirection The audio direction. Can be one of the following:
+ * {@link #DIRECTION_INVALID},
+ * {@link #DIRECTION_INACTIVE},
+ * {@link #DIRECTION_RECEIVE},
+ * {@link #DIRECTION_SEND},
+ * {@link #DIRECTION_SEND_RECEIVE},
+ * @param videoQuality The video quality. Can be one of the following:
+ * {@link #VIDEO_QUALITY_NONE},
+ * {@link #VIDEO_QUALITY_QCIF},
+ * {@link #VIDEO_QUALITY_QVGA_LANDSCAPE},
+ * {@link #VIDEO_QUALITY_QVGA_PORTRAIT},
+ * {@link #VIDEO_QUALITY_VGA_LANDSCAPE},
+ * {@link #VIDEO_QUALITY_VGA_PORTRAIT},
+ * @param videoDirection The video direction. Can be one of the following:
+ * {@link #DIRECTION_INVALID},
+ * {@link #DIRECTION_INACTIVE},
+ * {@link #DIRECTION_RECEIVE},
+ * {@link #DIRECTION_SEND},
+ * {@link #DIRECTION_SEND_RECEIVE},
+ * @param rttMode The rtt mode. Can be one of the following:
+ * {@link #RTT_MODE_DISABLED},
+ * {@link #RTT_MODE_FULL}
+ */
+ public ImsStreamMediaProfile(int audioQuality, int audioDirection,
+ int videoQuality, int videoDirection, int rttMode) {
+ mAudioQuality = audioQuality;
+ mAudioDirection = audioDirection;
+ mVideoQuality = videoQuality;
+ mVideoDirection = videoDirection;
+ mRttMode = rttMode;
+ }
+
/** @hide */
public ImsStreamMediaProfile() {
mAudioQuality = AUDIO_QUALITY_NONE;
diff --git a/telephony/java/com/android/internal/telephony/DcParamObject.java b/telephony/java/com/android/internal/telephony/DcParamObject.java
index 139939c..fc6b610 100644
--- a/telephony/java/com/android/internal/telephony/DcParamObject.java
+++ b/telephony/java/com/android/internal/telephony/DcParamObject.java
@@ -36,7 +36,7 @@
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(mSubId);
+ dest.writeInt(mSubId);
}
private void readFromParcel(Parcel in) {
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 494ee65..f4b85b2 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -92,6 +92,7 @@
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
+ private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save
private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
private static final String LAUNCH_FILE = "applaunch.txt";
private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
@@ -263,6 +264,8 @@
String.format("killall -s SIGUSR1 %s", appPkgName);
getInstrumentation().getUiAutomation().executeShellCommand(
sendSignalCommand);
+ // killall is async, wait one second to let the app save the profile.
+ sleep(PROFILE_SAVE_SLEEP_TIMEOUT);
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(launch.getCompilerFilter(), appPkgName));
}
diff --git a/tests/OdmApps/Android.mk b/tests/OdmApps/Android.mk
new file mode 100644
index 0000000..64fa653
--- /dev/null
+++ b/tests/OdmApps/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := OdmAppsTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_LIBRARIES := tradefed
+LOCAL_COMPATIBILITY_SUITE := device-tests
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/OdmApps/AndroidTest.xml b/tests/OdmApps/AndroidTest.xml
new file mode 100644
index 0000000..2f12838
--- /dev/null
+++ b/tests/OdmApps/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="Config for ODM apps test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="remount-system" value="true" />
+ <option name="push" value="TestOdmApp.apk->/odm/app/TestOdmApp/TestOdmApp.apk" />
+ <option name="push" value="TestOdmPrivApp.apk->/odm/priv-app/TestOdmPrivApp/TestOdmPrivApp.apk" />
+ <option name="post-push" value="stop; start; sleep 5" />
+ </target_preparer>
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="OdmAppsTest.jar" />
+ </test>
+</configuration>
diff --git a/tests/OdmApps/app/Android.mk b/tests/OdmApps/app/Android.mk
new file mode 100644
index 0000000..9eec0cc
--- /dev/null
+++ b/tests/OdmApps/app/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := TestOdmApp
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_SDK_VERSION := current
+include $(BUILD_PACKAGE)
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h b/tests/OdmApps/app/AndroidManifest.xml
old mode 100644
new mode 100755
similarity index 61%
rename from cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h
rename to tests/OdmApps/app/AndroidManifest.xml
index fcae35f..84a9ea8
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h
+++ b/tests/OdmApps/app/AndroidManifest.xml
@@ -1,4 +1,5 @@
-/*
+<?xml version="1.0" encoding="utf-8"?>
+<!--
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,23 +13,9 @@
* 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.
- */
+ -->
-#pragma once
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.odm.app">
+</manifest>
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class KernelUidCpuActiveTimeReader : public StatsPuller {
- public:
- KernelUidCpuActiveTimeReader();
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/tests/OdmApps/priv-app/Android.mk b/tests/OdmApps/priv-app/Android.mk
new file mode 100644
index 0000000..d423133
--- /dev/null
+++ b/tests/OdmApps/priv-app/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := TestOdmPrivApp
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_SDK_VERSION := current
+include $(BUILD_PACKAGE)
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h b/tests/OdmApps/priv-app/AndroidManifest.xml
old mode 100644
new mode 100755
similarity index 61%
copy from cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h
copy to tests/OdmApps/priv-app/AndroidManifest.xml
index fcae35f..031cf64
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h
+++ b/tests/OdmApps/priv-app/AndroidManifest.xml
@@ -1,4 +1,5 @@
-/*
+<?xml version="1.0" encoding="utf-8"?>
+<!--
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,23 +13,9 @@
* 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.
- */
+ -->
-#pragma once
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.odm.privapp">
+</manifest>
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class KernelUidCpuActiveTimeReader : public StatsPuller {
- public:
- KernelUidCpuActiveTimeReader();
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
new file mode 100644
index 0000000..de742b8
--- /dev/null
+++ b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.test.odm.apps;
+
+import com.android.tradefed.testtype.DeviceTestCase;
+
+public class OdmAppsTest extends DeviceTestCase {
+ /**
+ * Test if /odm/app is working
+ */
+ public void testOdmApp() throws Exception {
+ assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.app"));
+ }
+
+ /**
+ * Test if /odm/priv-app is working
+ */
+ public void testOdmPrivApp() throws Exception {
+ assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.privapp"));
+ }
+}
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index e396a63..8219150 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -427,6 +427,8 @@
printf(" new GZipSection(%d,", field->number());
splitAndPrint(s.args());
printf(" NULL),\n");
+ case SECTION_TOMBSTONE:
+ printf(" new TombstoneSection(%d, \"%s\"),\n", field->number(), s.args().c_str());
break;
}
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ddcf327..93fa598 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2076,11 +2076,15 @@
}
/**
- * Set the {@link ProxyInfo} for this WifiConfiguration.
+ * Set the {@link ProxyInfo} for this WifiConfiguration. This method should only be used by a
+ * device owner or profile owner. When other apps attempt to save a {@link WifiConfiguration}
+ * with modified proxy settings, the methods {@link WifiManager#addNetwork} and
+ * {@link WifiManager#updateNetwork} fail and return {@code -1}.
+ *
* @param httpProxy {@link ProxyInfo} representing the httpProxy to be used by this
- * WifiConfiguration. Setting this {@code null} will explicitly set no proxy,
- * removing any proxy that was previously set.
- * @exception throw IllegalArgumentException for invalid httpProxy
+ * WifiConfiguration. Setting this to {@code null} will explicitly set no
+ * proxy, removing any proxy that was previously set.
+ * @exception IllegalArgumentException for invalid httpProxy
*/
public void setHttpProxy(ProxyInfo httpProxy) {
if (httpProxy == null) {
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index d119579..457e904 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -16,7 +16,7 @@
package android.net.wifi.rtt;
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.ACCESS_WIFI_STATE;
import static android.Manifest.permission.CHANGE_WIFI_STATE;
import static android.Manifest.permission.LOCATION_HARDWARE;
@@ -109,7 +109,7 @@
* @param executor The Executor on which to run the callback.
* @param callback A callback for the result of the ranging request.
*/
- @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
+ @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
public void startRanging(@NonNull RangingRequest request,
@NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback) {
startRanging(null, request, executor, callback);
@@ -128,7 +128,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE,
+ @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE,
ACCESS_WIFI_STATE})
public void startRanging(@Nullable WorkSource workSource, @NonNull RangingRequest request,
@NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback) {
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index 11ac058..e639282 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -11,7 +11,7 @@
<ul>
<li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
<li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
- <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
+ <li>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</li>
</ul>
<p>Usage of the API is also gated by the device's Location Mode: whether it permits Wi-Fi based
location to be queried.</p>